简体   繁体   中英

Implementing interface in different assemblies

I have an interface and class like this

public interface ICustomerEx
{
   void Load(DataRow row);
}

public class Customer:ICustomerEx
{
   public string Name{get;set;}
   public string Address{get;set;}

   void Load(DataRow row)
   {
    Name = (string)row["name"];
    Address = (string)row["address"];
   }
}

Now I'm building this as a class library and add to another project as a reference. In that project there's a class called UiCustomer that implements from the same refereced interface ICustomerEx In this class it has its own property and load that property from its load method.

public class UiCustomer:ICustomerEx
{
   public string Telephone{get;set;}

   void Load(DataRow row)
   {
    Telephone=(string)row["tele"];
   }
}

Now is there any way to implement my first class's(that build as a class library) Load method to load Ui project's properties after loading it's own properties by using like Dependency Injection.

eg.

public class Customer:ICustomerEx
{
   public string Name{get;set;}
   public string Address{get;set;}

   void Load(DataRow row)
   {
    Name = (string)row["name"];
    Address = (string)row["address"];

    //Call load methods in other places that Interface implemented
   }
}

It depends what you want. Using separate classes as you have now, you'd need to dependency-inject a list of ICustomerEx objects into each Customer, but then you'd end up with a bunch of different objects each of which would have only a subset of the relevant properties. It sounds like inheritance + the template method pattern might be a better fit:

public class Customer:ICustomerEx
{
   public string Name{get;set;}
   public string Address{get;set;}

   void Load(DataRow row)
   {
       this.Name = (string)row["name"];
       this.Address = (string)row["address"];
       this.DoMoreLoading(row);
   }

   // this method is defined as a no-op in the base class, but it provides an extension point
   // for derived classes that want to load additional properties
   protected virtual void DoMoreLoading(DataRow row) { }
}

// note that now UiCustomer extends Customer (and thus still implements ICustomerEx
public class UiCustomer : Customer
{
   public string Telephone { get; set; }

   protected override void DoMoreLoading(DataRow row)
   {
       this.Telephone = (string)row["tele"];
   }
}

// usage
var uiCustomer = new UiCustomer();
uiCustomer.Load(row); // populates name, addr, and telephone

To support instantiating the customer on the library side, you'll need some way to make the library aware of the UiCustomer class.

One way to do this would be to register an ICustomerEx with an IOC container and then resolve the instance using dependency injection:

// in the UI code (this is code for the Autofac IOC container):
ContainerBuilder cb = ...
cb.RegisterType<UiCustomer>().As<ICustomerEx>();
cb.RegisterType<AServiceThatNeedsACustomer>();

// in the library code
public class AServiceThatNeedsACustomer {
    private readonly ICustomerEx customer;
    // the customer will get injected by the IOC container
    public AServiceThatNeedsACustomer(ICustomerEx customer) {
        this.customer = customer;
    }
}

Alternatively, you could use a factory pattern:

// in the library:
public static class CustomerFactory {
   private static volatile Func<ICustomerEx> instance = () => new Customer(); 
   public static Func<ICustomerEx> Instance { get { return instance; } set { instance = value; } }        
}

// then to get a customer
var cust = CustomerFactor.Instance();
cust.Load(row);

// in the UI code:
CustomerFactory.Instance = () => new UiCustomer();

You can call the other implementations like this

In the assembly that contains the interface ICustomerEx you can add a registry-class that stores instances of ICustomerEx like this

(Note this is pseudocode to show how it could go.)

public class CustomerRegistry : ICustomerEx {
    // singelton
    public static final CustomerRegistry theRegistry = new CustomerRegistry();

    private ArrayList<ICustomerEx> customers = new ArrayList<ICustomerEx>();
    public void RegisterCustomer(ICustomerEx customer) {
       customers.add(customer);
    }

    public void Load(DataRow row)
    {
       foreach(ICustomerEx customer in customers) {
          customer.Load(row);
       }
    }
} 

every implementation of ICustomerEx needs a call to the registry

CustomerRegistry.theRegistry.RegisterCustomer(new UiCustomer());

in your main customer class you use the registry to call the other loads

public class Customer:ICustomerEx
{
 void Load(DataRow row)
 {
   CustomerRegistry.theRegistry.Load(row);
 }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM