views:

2034

answers:

7

Hi,

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

A: 

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

Nathan
A: 

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.

Odd
+1  A: 

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;
    }
}
Mark Brackett
+1  A: 

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;
    }
}
Rohan West
A: 

Hi,

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 abcRepository = new RepositoryManager(); RepositoryManager xyzRepository = new RepositoryManager();

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.CreateNew(IMedicament, string)' and 'RepositoryManager.CreateNew(IRefund, string)'

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

-Mark

Mark Nijhof
A: 

How about making IRefund and IMedicament implement a shared interface that both have Id properties?

jayrdub
A: 

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).

Kind Regards, Keld Ølykke

Keld Ølykke