简体   繁体   中英

C# - Instantiate a class depending on a provided interface in a generic class

I have a generic function which gets a interface as a type, now in one condition I have to create a new class depending on the interface. I have been thinking about it and a way to solve it would be to use an IoC but I was hoping there would be an other way because an IoC seems a bit like an overkill.

below is an attempt using the visitor pattern:

public class RepositoryManager<T> : IRepositoryManager<T> where T : class, new()
{
    public T GetOrCreate(string id)
    {
        T item = (T)CreateNew(new T(), id);
        return item;
    }
}

If instead of an interface I was getting an object then I could use the visitor pattern to figure out what class to instantiate but I can't seem to figure this out depending on the interface provided.

An other idea I had was if I can make the where declaration like an or?

public class RepositoryManager<T> : IRepositoryManager<T> where T : class, Iabc or Ixyz, new()

I hope the question is clear :)

-Mark


Thanks for the reply's.

The problem is that the method can have many different interfaces assigned to it for example:

RepositoryManager class:

private static IMedicament CreateNew(IMedicament emptyType, string id)
{
    return new Medicament { Id = id };
}
private static IRefund CreateNew(IRefund emptyType, string id)
{
    return new Refund { Id = id };
}

RepositoryManager<Iabc> abcRepository = new RepositoryManager<Iabc>();
RepositoryManager<Ixyz> xyzRepository = new RepositoryManager<Ixyz>();

Iabc abc = abcRepository.GetOrCreate("12345");
Ixyz xyz = xyzRepository.GetOrCreate("12345");

so using T item = (T)CreateNew(new T(), id); won't work because I have to tell it that T can either be of type Iabc or Ixyz but when I do that I get the following error:

The call is ambiguous between the following methods or properties: RepositoryManager<T>.CreateNew(IMedicament, string) and RepositoryManager<T>.CreateNew(IRefund, string)

It would be nice if I get this working besides just copying the code several times.

And why doesn't this work?

public class RepositoryManager<T> : IRepositoryManager<T> where T : Ixyz, new()
{
    public T GetOrCreate(string id)
    {
        T item = (T)CreateNew(new T(), id);
        return item;
    }
}

An alternative, if you can't use new() is to pass in a delegate to create the object (or a compatible type):

public class RepositoryManager<T> : IRepositoryManager<T> where T : Ixyz
{
    private Func<T> _tConstructor;

    public RepositoryManager(Func<T> tConstructor)
    {
      this._tConstructor = tConstructor;
    }

    public T GetOrCreate(string id, )
    {
        T item = (T)CreateNew(this._tConstructor(), id);
        return item;
    }
}

I'm not sure i understand the question fully but i've used something like this before.

public class Repository
{
    public T Create<T>(string id) where T : class
    {
        return Activator.CreateInstance(typeof(T), new[] { id }) as T;
    }
}

If I understand what your question is, basically you want to do (in a sense) what RhinoMocks does, except that RhinoMocks actually dynamically creates a class from an interface, where as you want to use an existing class.

I'm not familiar enough with the code to know how RhinoMocks accomplishes this, but as it is opensource, you might be able to get some ideas but looking at its source code.

http://ayende.com/projects/rhino-mocks/downloads.aspx

如何使IRefund和IMedicament实现一个都具有ID属性的共享接口?

I came across this problem myself just the other day. The probem is that you don't know how many parameters the constructor takes. On the assumption that it takes none, the following code will work.

public void Method<T>()
{
  Type type = typeof(T);

  T newObject = (T)type.GetConstructor(new System.Type[] { }).Invoke(new object[] { });
}

The example uses reflection. If you need parameters then you can put objects into the arrays created in the code.

Maybe the following could work for you? 1) create a dictionary where type is your interface (T parameter) and object is a dummy instance of the object that can be created, 2) let your dummy object be the factory of new objects that implements T.

Your RepositoryManager just need to initialize the dictionary with the supported interface-object pairs, where multiple interfaces can map to same object (if needed).

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