This seems like an age-old question, but simply can't find what I'm looking for. Here's my current code with things I've tried.
private async Task<T> HandleFileCreate<T>(Guid tableId, IFormFile file, DocumentType documentType)
where T : DocumentLibrary
{
// This works fine and gets the correct type
Type repoType = _unitOfWork.GetType().GetProperty(typeof(T).Name + "Repository").PropertyType;
// This works fine and creates an instance of my document
T document = (T)Activator.CreateInstance(typeof(T));
// Throws up error: "No parameterless constructor defined for this object."
object instance = Activator.CreateInstance(repoType);
// Throws up error: "Object does not match target type."
repoType.GetMethod("Create").Invoke(repoType, new object[] { document });
}
It seems a bit chicken and egg because I can't invoice "Create" it seems without the CreateInstance, in which I can't do because of IoC.
This is really annoying because I've already got an instantiated property in _unitOfWork which relates directly to my relevant GenericRepository, I just can't figure out how to access it? I shouldn't even have to re-instantiate it.
Rader then using reflection(Always a bad idea) I would recommend doing something like this
public static T Create<T>(IDocumentLibraryCreator<T> repo)// You can add you params here
where T: DocumentLibrary, new()
{
var newItem = new T();
repo.Create(newItem);
//Do your stuff here
return newItem;
}
public interface IDocumentLibraryCreator<T> where T : DocumentLibrary
{
Task Create(T document);
}
public abstract class DocumentLibrary
{
}
Because all you will get with reflection is runtime exceptions and not compile time exceptions. No need for reflection. Your repo will need to implement IDocumentLibraryCreator<T> interface but if you did IRepository in a good way you should have something like this already.
You will need to pass the instance created in the uof class if you need the work to be done in a single Unite of work.
Related
I am trying to implement a complex builder to help my testing context. To do that I refactored my code to have a method :
public TestContext Add<T>(Action<IBuilder<T>> configurator) where T : class, new()
{
IBuilder<T> builder = CreateBuilderOf<T>();
configurator(builder);
T item = builder.GetItem();
RepositoryOf<T>().Insert(item);
SetCurrent(item);
return this;
}
The problem arises when I need to specify the configuration when calling the method :
TestContext.Instance.Add<Person>(personBuilder => ((PersonBuilder)personBuilder).Name("SMITH"));
I need to be able to use type specific methods in the configurator, which are implemented by the concrete builders, such as :
public PersonBuilder : IBuilder<Person>
{
private Person Item;
public PersonBuilder() { Item = new Person(); }
public Name(string mame) { Item.Name = name; }
public Person GetItem() { return Item; }
}
Apparently, passing an Action<PersonBuilder> as an Action<IBuilder<Person>> is not allowed, even though PersonBuilder implements IBuilder<Person>, hence the cast.
I would very much like to either :
Need not to cast inside the lambda but rather at the start of it, e.g.
(PersonBuilder personBuilder) => personBuilder.Name("SMITH"), but that boils down to being an instance of Action<PersonBuilder> and therefore is equally invalid;
Use a function such as BuildSimplePerson(PersonBuilder builder) in Add's argument : Add<Person>(BuildSimplePerson)
I think I can do a type casting through two BuildSimplePersons implementations such as :
private void BuildSimplePerson(IBuilder<Person> builder)
{
BuildSimplePerson(builder as PersonBuilder);
}
private void BuildSimplePerson(PersonBuilder builder)
{
builder.Name("SMITH");
}
But that is not really an elegant solution.
I also realize passing Action<PersonBuilder> as an Action<IBuilder<Person>> is incorrect because we don't know if the argument to that function will truly be a PersonBuilder or any other implementation of IBuilder<Person>.
How can I do better ?
As my comment already states, the problem is that your current code assumes that CreateBuilderOf<T> returns a PersonBuilder but it could actually return anything that implements IBuilder<Person> in which case your cast would fail.
Your code looks like it is generic, but in fact, it is not. You always want to work on the concrete class (PersonBuilder) and not on the general interface IBuilder<Person>.
My understanding is, that you want one generic Add<T> method to avoid having to repeat that code inside it for each type.
Here is my approach:
public TestContext Add<T>(IBuilder<T> builder) where T : class, new()
{
T item = builder.GetItem();
RepositoryOf<T>().Insert(item);
SetCurrent(item);
return this;
}
You would call it like this:
TestContext.Instance.Add<Person>(CreatePersonBuilder().Name("SMITH"));
Obviously, you would need to have a CreateXBuilder method for each type that you want to be able to add. However, I think you already have this at least implicitly, because I would assume that your CreateBuilderOf<T> method is one huge switch statement anyway.
If you don't want to create such methods, another approach to get the builder would be a generic method like so:
CreateBuilder<PersonBuilder>()
But really, this is actually nothing more than a new PersonBuilder(), so you actually could simply go with
TestContext.Instance.Add<Person>(new PersonBuilder().Name("SMITH"));
The Configure method would be very similar:
TestContext.Instance.Configure<Person>(id, p => new PersonBuilder(p).Name("SMITH"));
This would pass the ID, which the Configure method would use to look up the object, which in turn is passed to the callback. So the second parameter of Configure would not be a Action<IBuilder<T>> but an Action<T>.
This approach has another advantage over your existing code:
Your existing code assumes not just that PersonBuilder will be the implementation used for IBuilder<Person>. No, your code also assumes that it has a constructor without parameters and one which takes a Person. These assumptions are impossible for the compiler to verify.
With the code I showed above, a builder implementation could take additional parameters without problems and the compiler would verify that everything is alright.
FYI: the verbose preamble is to help explain why I am using Activator.CreateInstance. I have a number of entities (objects corresponding to database column information) that are "contained" in multiple databases, each of which has a different table/column setup. So I am able to retrieve an entity from each database, but the way I retrieve it is different per database. The database type is not known till runtime and could vary throughout execution. I have created the following setup:
First define the query operations each entity should support and each entity reader should support these operations.
public abstract class Operations<T> {
public delegate T findDelegate(int id);
public findDelegate find;
}
// there are many of these N=1,2,..., but here is one
// use abstract class since implementation of queries should be done by handlers
public class EntityNReader : Operations<EntityN> {
public Reader();
}
Define an interface for "Handler" classes, i.e. these classes implement the query operations listed above.
public interface IHandler<T> {
public string find(int id);
}
// there are many of these N,M=1,2..., but here is one
// use of interface is to force handlers to implement all query types
public class EntityNHandlerForDbTypeM : IHandler<EntityN> {
public string find(int id) {/*whatever*/}
}
This allows the developers to create a single class for handling EntityN query operations for DbTypeM. Now, create a Database class that contains the reader objects and binds the handler methods to the reader delegates.
public class Database {
// there are many of these, but here is one
public EntityNReader EntitiesN;
public Database(string dbType) {
// this is called for each EntityNReader
bindHandlers<Reader, TypeN>(MyReader, dbType);
// ...
// nullreferenceexception
EntitiesN.find(0);
}
// this is a factory that also performs late binding
private void bindHandlers<T,K>(T reader, string dbTypeM)
where T: Operations<K>, new()
{
// create instance of EntityNReader
r = (T)Activator.CreateInstance(typeof(T));
// r != null
// create instance of handler
IHandler<K> h = (IHandler<K>)(Activator.CreateInstance(
Type.GetType("namespace.to.EntityNHandlerForDbTypeM"),
new object[] { this }
));
// bind delegates
r.find = h.find;
}
}
As you can see in Databases constructor, the way the code is written now, I get a NullReferenceException even though instance r of EntityNReader is created and (verified to be) not null.
However, if I instantiate EntitiesN where it is declared in Database instead of within bindHandlers, the code compiles and everything works. The reason I don't just do this is that (subsequently) I would like to conditionally create readers/handlers inside of bindHandlers at the time the Database class is instantiated.
What is happening here? Link to actual code if necessary.
P.S. I am relatively new to programming, so I am open to hearing how an experience developer might design this component (especially if I am heading down the wrong path).
I realize your code was just samples, but I spotted this right off the bat...
if (supports[typeof(Entity1).Name]) { bindHandlers<Entity1Reader, Entity1>(Entities1, CamaDbType); }
if (supports[typeof(Entity2).Name]) { bindHandlers<Entity1Reader, Entity1>(Entities1, CamaDbType); }
Is it possible that you have a simple copy/paste mistake? Notice that Entities1 is passed in for both bindHandlers calls.
I have this class
public class MyViewModel<T> where T : class
{
public MyViewModel(
Func<IEnumerable<T>, MyService<T>> myServiceFactory,
IEnumerable<T> list)
{
}
}
and I need to register the Func in the bootstrapper.
I tried something like
builder.Register<Func<IEnumerable<T>, MyService<T>>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return collection => ctx.Resolve<MyService<T>>(collection);
});
but I can't get it working. Can anyone help me?
As you already noticed, what you're trying to do does not compile. Without defining the T somewhere, the C# compiler doesn't understand. Without a staticly defined T, you would have to define the types using reflection, but you'll hit limits of Autofac and C# pretty soon. You're code becomes very nasty. Instead, you'll have to extract this code in a helper method:
private static void RegisterMyServiceFactory<T>(IContainerBuilder builder) {
builder.Register<Func<IEnumerable<T>, MyService<T>>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return collection => ctx.Resolve<MyService<T>>(collection);
});
With this method need to call this method for every T you need in your application:
RegisterMyServiceFactory<Customer>(builder);
RegisterMyServiceFactory<Order>(builder);
RegisterMyServiceFactory<Employee>(builder);
This solution isn't particularly nice, but this is because you're missing an abstraction. Instead of letting your consumers depend upon Func<IEnumerable<T>, MyService<T>>, you should create a specific abstraction for consumers to depend upon:
public interface IServiceFactory<T> {
MyService<T> Resolve(IEnumerable<T> collection);
}
And embed your code in an IServiceFactory<T> implementation:
private sealed class AutofacServiceFactory<T> : IServiceFactory<T> {
private readonly IComponentContext context;
public AutofacServiceFactory(IComponentContext context) {
this.context = context;
}
public MyService<T> Resolve(IEnumerable<T> collection) {
return context.Resolve<MyService<T>>(collection);
}
}
You can register this open generic type as follows:
builder.RegisterGeneric(typeof(AutofacServiceFactory<>))
.As(typeof(IServiceFactory<>));
If the builder.Register code is executed by an instance of a MyViewModel it could/should work.
Otherwise it depends on how/if the T is declared in your particular context and you'll need to supply more info.
Anyway, your problem does not seem to be related to autofac in anyway. It's related to the use of generics. The Register method is indeed a generic method, but the generic parameter has to be ultimately translated to a concrete type when the call is made. So, unless T is properly declared in the context of the call to builder.Register then it won't work as it seems you are trying to register a whole range of types.
I created a little abstract domain to illustrate the problem I am facing, so there it is.
There is a medieval game, where the players are generals of their army and the entire battle is mostly affected by the battle plan, which is made before the battle begins, in let's say preparation mode.
To achieve what's needed, I created an interface IBattleUnit and kept things pretty simple:
public interface IBattleUnit
{
void Move();
void Attack();
string Salute();
}
Having three types of units will do the job for now, so Archer.cs, Pikeman.cs and Swordsman.cs implement the interface in pretty much the same way:
public class Swordsman : IBattleUnit
{
private Swordsman() {}
public void Move()
{
//swordsman moves
}
public void Attack()
{
//swordsman attacks
}
public string Salute()
{
return "Swordsman at your service, master.";
}
}
Note the private constructor, it is intended for battle units to be recruited only in Barracks, this is the generic factory
public static class Barracks<T> where T : class, IBattleUnit
{
private static readonly Func<T> UnitTemplate = Expression.Lambda<Func<T>>(
Expression.New(typeof(T)), null).Compile();
public static T Recruit()
{
return UnitTemplate();
}
}
Note: precompiled lambda expressions for the empty constructor make (on my machine) unit creation faster, and whereas the army can get really big, fast generic creation is exactly what I want to achieve.
For having covered everything a battle needs to be started, the BattlePlan explanation is the only missing part, so here we come:
public static class BattlePlan
{
private static List<Type> _battleUnitTypes;
private static List<Type> _otherInterfaceImplementors;
//...
private static Dictionary<string, string> _battlePlanPreferences;
private static Type _preferedBattleUnit;
private static Type _preferedTransportationUnit;
//...
static BattlePlan()
{
//read the battle plan from file (or whereever the plan init data originate from)
//explore assemblies for interface implementors of all kinds
//and finally fill in all fields
_preferedBattleUnit = typeof (Archer);
}
public static Type PreferedBattleUnit
{
get
{
return _preferedBattleUnit;
}
}
//... and so on
}
Now if you have reached this, you are aware of the whole domain - it even compiles and everything looks bright, until...
Until now: I create a console application, add references to the above mentioned, and try to profit from what's under the hood.
For complete description of my confusion, I note what IS WORKING first:
If I want the Barracks to give me a specific BattleUnit, I can instantiate it and let it fight, move and salute. If the instantiation is done this way:
IBattleUnit unit = Barracks<Pikeman>.Recruit();
If I want to know what is the prefered unit based on battle plan, I can get it, I can ask for its AssemblyQualifiedName, I get the Type (in fact it is Archer, just as it stays in BattlePlan) , long story short, I get what I expect to, when I call:
Type preferedType = BattlePlan.PreferedBattleUnit;
And here, when I expect the BattlePlan to supply me with a Type and me just passing the Type to Barracks in order to instantiate some kind of Unit, VisualStudio2012 (resharper of current version) stops me and does not compile the code, while the code, that leads to the error is:
Type t = Type.GetType(BattlePlan.PreferedBattleUnit.AssemblyQualifiedName);
IBattleUnit u = Barracks<t>.Recruit();
No matter what I do, no matter whether I pass the t, or pass it as typeof(t), or try converting it to IRepository ... I still end up not being able to compile such code, with (at least) two errors in the error list:
Error 1 Cannot implicitly convert type 't' to 'BattleUnits.cs.IBattleUnit' Program.cs
Error 2 The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?) Program.cs
So to the actual questions:
Is there some way, I could pass the type to Barracks, not having to change underlying infrastructure?
Or is there anything I am doing wrong by design?
I have spent the last two days googling around and still, with the only clear way being changing the Barracks, which in fact is what I would not want to.
EDIT no.1: When re-thinking the concept and everything : IBattleUnit was first described as a set of core battle actions every Unit will be able to do (and we want it to be this way). I did not want to introduce base classes, just because I knew, there could possibly be GroundUnitBase and FlyingUnitBase abstract classes for the sake, we would like to have clear and logical design... But there absolutely has to be only one static Barracks.
Still for the BattleUnits - putting one base class in my eyes now seems could change the things for code being runnable and I'm right on my way of trying that out ... reading, what I wrote made me think about UnitBase class could possibly help not even the design but in some way its compilability. So this is the first idea in my mind after rethinking what's written.
You don't really need Barracks to be generic.
This solution doesn't use reflection so it's much more efficient:
public static class Barracks
{
private static readonly IDictionary<Type, Func<IBattleUnit>> FactoryMethods = new Dictionary<Type, Func<IBattleUnit>>();
public static void Register<T>(Func<IBattleUnit> factory) where T : IBattleUnit
{
FactoryMethods.Add(typeof(T), factory);
}
public static IBattleUnit Recruit<T>() where T : IBattleUnit
{
return Recruit(typeof (T));
}
public static IBattleUnit Recruit(Type type)
{
Func<IBattleUnit> createBattleUnit;
if (FactoryMethods.TryGetValue(type, out createBattleUnit))
{
return createBattleUnit();
}
throw new ArgumentException();
}
}
public class Swordsman : IBattleUnit
{
static Swordsman()
{
Barracks.Register<Swordsman>(() => new Swordsman());
}
}
public static class Barracks
{
public static IBattleUnit Recruit(Type preferredType)
{
return (IBattleUnit)typeof(Barracks<>).MakeGenericType(preferredType).GetMethod("Recruit", BindingFlags.Public|BindingFlags.Static).Invoke(null,null);
}
}
then call
Barracks.Recruit(BattlePlan.PreferredBattleUnit)
You can do this using reflection, something like this:
IBattleUnit unit = typeof(Barracks).GetMethod("Recruit").MakeGenericType(BattlePlan.PreferedBattleUnit).Invoke(null, null) as IBattleUnit;
If you have an instance of the PreferedBattleUnit you simply need to use the dynamic keyword. Please have a look at this question (John Skeet answer): (EDIT: This might not be very helpful as your method is not generic)
Pass concrete object type as parameter for generic method
If you don't have an instance of the object than have a look at the following question (again, John Skeet answer):
Generics in C#, using type of a variable as parameter
My strategy would be to create a Dictionary<Type, Barracks<IBattleUnit>>, assuming you intend to have all the barracks defined before you try to retrieve from them. That way you can match by the key and cast safely.
This would require the Barracks<> to not be a static class. Unless you have very specific reasons like some kind of external resource you're managing (and arguably even then), you probably have no need for a static class.
While it may seem like creating statics for all of these will make everything easier, ultimately you create a dependency on a resource that may change. If you invent another unit type, you have to register it with the barracks, which is in no real way different than the reason you don't want to make base classes, and if you forget you'll throw exceptions, which is even worse, because it violates the Principle of Least Surprise.
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 "driss" 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.