instantiate a class implementing a generic interface using reflection
I have the following in a business logic assembly:
public class BusinessEntity
{
...
}
public class Customer : BusinessEntity
{
...
}
public interface IEntityManager <T> where T : BusinessEntity
{
T SaveData(T oData);
}
public CustomerEntityManager : IEntityManager <Customer>
{
Customer SaveData(Customer o)
{
...
}
}
I am forced to load the above assembly (due to a couple of obvious reasons) in my current project through reflection and instantiate CustomersEntityManager
. Imagine that I am writing a method as follows:
public class EntityFactory
{
public static IEntityManager<BusinessEntity> GetManagerInstance(string EntityName)
{
var asm = GetAssembly(); // imagine that I loaded the assembly somehow
EntityName = "Customer"; // just imagine
object o;
// DO NOT KNOW WHAT TO WRITE HERE.
return o as IEntityManager<BusinessEntity>; // this needs to be an instance of CustomerEntityManager.
}
}
I have the option to modify business assembly. But the instance creation needs to be in my current project and I have to load the business assembly using reflection. All the data types will be known only at run-time.
I may be missing some fundamental things or probably doing wrong coding. Please help me out on this.
UPDATE:
Followed "dris开发者_开发知识库s" suggestion, like following:
string fullTypeName = "Your.Namespace." + EntityName + "EntityManager";
object o = Activator.CreateInstance(asm.FullName, fullTypeName);
Looks like it created the instance. However, it ended up with an error:
Cannot cast 'o' (which has an actual type of 'CustomerEntityManager') to 'IEntityManager'
when the following statement is getting executed:
return o as IEntityManager<BusinessEntity>
Thanks
You need to construct the full type name somehow, so that you can get the Type
instance representing the type. You might decide that the type name relies on a convention, such that you could find the full type name as:
string fullTypeName = "Your.Namespace." + EntityName + "EntityManager";
object o = Activator.CreateInstance(asm.FullName, fullTypeName);
Then it is just a matter of calling Activator.CreateInstance, as you see.
However, I would highly recommend you looking into using an IoC framework for solving this problem.
Re: your comment:
You can't cast CustomerEntityManager to IEntityManager, because that is not what it implements - it only implements IEntityManager. If the cast was allowed, type safety would be broken (you could pass in a BusinessEntity, when the implementation clearly expects a Customer, or, that is at least what the contract says. (Co/contra variance can't save you here because T goes both in and out of IEntityManager).
Forget about using low-level reflection at your own, a lot of not very convenient work. Use an IoC framework if you can, i.e. StructureMap. With StructureMap you'll just need to create a Registry that knows all the dependencies (such as CustomersEntityManager
is our implementation for IEntityManager<Customer>
). It looks more less like that:
For<IEntityManager<Customer>>().Use<CustomersEntityManager>()
And now if you ask your StructureMap container for an implementation of IEntityManager<Customer>
, you'll get CustomersEntityManager
:
ObjectFactory.GetInstance<IEntityManager<Customer>>(); // will return instance of CustomersEntityManager
If you don't know the requested type at compile time, you can ask for the entity manager using plain Type
instance:
string entityName = "Customer";
Type entityType = Type.GetType(entityType);
Type requestedType = typeof(IEntityManager<>).MakeGenericType(new[] { entityType });
ObjectFactory.GetInstance(requestedType); // will also return CustomersEntityManager instance
Registry can be defined in your assembly, without touching the business assembly.
Checkout Activator.CreateInstance()
Object o = Activator.CreateInstance (asm.FullName, EntityName );
will give you an instance of the Customer
. I'm not sure how you would go from Customer
to CustomerEntity
but I'm sure you can work that part out.
精彩评论