Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common interface for two third-party classes I don't control. External Polymorphism?

I need a little pattern direction here. New to C#.

I'm working with a third-party development kit that wraps a web service. There are two specific classes I deal with that, while relatively similar, are in two different namespaces in the dev kit and there's no common base class. I'd like to program against a common interface for them both however. I haphazardly threw together an implementation that essentially wraps the wrapper, but I feel rather certain it's not the most efficient method due to the incessant type casting.

I've been digging through articles on adapters, interfaces, extension methods, etc., but I'm running low on time, so if I could get a push in one direction that'd be greatly appreciated.

using ThirdParty.TypeA.Employee;
using ThirdParty.TypeB.Employee;

public class Employee
{
     private object genericEmployee;

     private EmployeeType empType;

     public enum EmployeeType
     {
          TypeA = 0;
          TypeB = 1;
     }   

     public Employee(Object employee, EmployeeType type)
     {
         genericEmployee = employee;
         empType = type;
     }

     public String Name
     {
         if (empType == EmployeeType.TypeA)
             return (ThirdParty.TypeA.Employee)genericEmployee.Name;
         else
             return (ThirdParty.TypeB.Employee)genericEmployee.Name;
     }

     public String Age
     {
         if (empType == EmployeeType.TypeA)
             return (ThirdParty.TypeA.Employee)genericEmployee.Age;
         else
             return (ThirdParty.TypeB.Employee)genericEmployee.Age;
     }
 }

Rev 2:

class EmployeeTypeAAdapter : TypeA, IEmployeeAdapter
{
    TypeA _employee;
    public EmployeeTypeAAdapter(TypeA employee) 
    { 
         _employee = employee
    }

     public String Name
     {
        get { return _employee.Name; }  
        set { _employee.Name = value; }
     } 

      public String Balance
      {
        get
        {
            if (_employee.Balance != null)
            {
                decimal c = _employee.Balance.Amount;
                return String.Format("{0:C}", c);
            }
            else
            {
                return "";
            }
          }
       }  

       //...
}

class EmployeeTypeBAdapter : TypeB, IEmployeeAdapter
{
    TypeB _employee;
    public EmployeeTypeAAdapter(TypeB employee) 
    { 
         _employee = employee
    }

     public String Name
     {
        get { return _employee.Name; }  
        set { _employee.Name = value; }
     } 

      public String Balance
      {
        get
        {
            if (_employee.Balance != null)
            {
                decimal c = _employee.Balance.Amount;
                return String.Format("{0:C}", c);
            }
            else
            {
                return "";
            }
          }
       }  

     //....
}
like image 904
RyanMac Avatar asked Jan 23 '13 18:01

RyanMac


2 Answers

Try this approach:

public interface IEmployeeAdapter
{
    string Age { get; set; }
    string Name { get; set; }
}

class EmployeeTypeAAdapter : TypeA, IEmployeeAdapter
{
    public EmployeeTypeAAdapter(TypeA employee) { }
}

class EmployeeTypeBAdapter : TypeB, IEmployeeAdapter
{
    public EmployeeTypeBAdapter(TypeB employee) { }
}

public static class EmployeeAdapterFactory
{
    public static IEmployeeAdapter CreateAdapter(object employee, EmployeeType type)
    {
        switch (type)
        {
            case EmployeeType.TypeA: return new EmployeeTypeAAdapter((TypeA)employee);
            case EmployeeType.TypeB: return new EmployeeTypeBAdapter((TypeB)employee);
        }
    }

    // or without enum

    public static IEmployeeAdapter CreateAdapter(object employee)
    {
        if (employee is TypeA) return new EmployeeTypeAAdapter((TypeA)employee);
        if (employee is TypeB) return new EmployeeTypeABdapter((TypeB)employee);
    }

    // or better introduce sort of type map
}

Another proper name is EmployeeProxy, as you prefer.

like image 61
abatishchev Avatar answered Nov 05 '22 07:11

abatishchev


What you're trying to do is known as Duck typing. You can do this using adapter classes and a shared interface, but creating these adapters manually requires a lot of repetitive glue code. One way you can get around writing the glue code is to construct the adapter type dynamically. You can do this yourself via IL Emit (a worthwhile exercise if you've never had a chance to play with it before, though there can be quite a few boundary cases to consider.) If you're just interested in getting it working, however, you might check out this project as a place to start. The C# 'dynamic' type could also be used (and winds up doing some of the same code generation behind the scenes), but it doesn't give you a reference you can pass around to non-dynamic code as if it were an interface type.

like image 32
Dan Bryant Avatar answered Nov 05 '22 08:11

Dan Bryant