I have a class that takes an interface as a constructor argument. There are two implementations of this interface and I want to decide what implementation to use at runtime based on a variable.
The problem is that the class above is deep in an object heirarchy that is resolved by Autofac and so I can't pass in the argument.
Somehing like below is what I am trying to achieve.
public interface IInterface1 {}
public interface IInterface2 {}
public class Class1 : IInterface2
{
public Class1(IInterface1 interface1)
{
}
}
public class Class2
{
public Class2(IInterface2 interface2)
{
}
}
public class Class3
{
public void GetClass2Instance(string interface1ImplementationToChoose)
{
// want to change which implementation of IInterface1 is resolved based on the interface1ImplementationToChoose variable
var class2 = container.Resolve<Class2>();
}
}
Any ideas?
UPDATE:
To clarify, this is an existing object hierarchy that is used by existing applications that work fine. Also, the object model is much larger than the one shown in this example. As a result I don't really want to have to pass down a factory to each constructor in the object graph to be used by a class deep in that graph.
Is there a way of getting a different implementation of IInterface1 passed into Class1 without Class2 knowing anything about it?
Thanks
Yes, inject a factory that hides how the types are chosen:
public class Class3
{
private Func<string, Class2> _class2Factory;
public Class3(Func<string, Class2> class2Factory)
{
_class2Factory = class2Factory;
}
public void GetClass2Instance(string interface1ImplementationToChoose)
{
var class2 = _class2Factory(interface1ImplementationToChoose);
}
}
And then the container setup, something along these lines:
builder.RegisterType<Implementation1>().Named("imp1").As<IInterface1>();
builder.RegisterType<Implementation2>().Named("imp2").As<IInterface1>();
builder.Register<Func<string, Class2>>(c =>
{
var context = c.Resolve<IComponentContext>();
return imp => new Class2(context.Resolve<IInterface1>(imp));
});
builder.RegisterType<Class3>();
You can now use Class3 like this:
public class Class4
{
public Class4(Class3 class3)
{
var class2with1 = class3.GetClass2Instance("imp1");
var class2with2 = class3.GetClass2Instance("imp2");
}
}
NOTE: I have assumed that you meant that Class2 should be injected with varying implementations of the same interface IInterface1. Your sample is a bit confusing since you are showing two classes that implements different interfaces.
Related
I'm trying to figure out how to use multiple implementation of a base class with generics via dependency injection in .net core.
My base class is using generics so I can have different types of List in my response Dto.
I have successfully used many interface and base class implementations when there are no generics involved.
What I've tried so far.
Base class
public abstract class GeneratorBase<T>
{
public abstract ProcessorResponse<T> Process();
}
Response dto
public class ProcessorResponse<T>
{
public ProcessorResponse()
{
Data = new List<T>();
}
public List<T> Data { get; set; }
}
Implementation number 1
public class ConfigurationGenerator : GeneratorBase<ConfigurationModel>
{
public override ProcessorResponse<ConfigurationModel> Process()
{
return new ProcessorResponse<ConfigurationModel>();
}
}
Implementation number 2.
public class ApplicationGenerator : GeneratorBase<ApplicationModel>
{
public override ProcessorResponse<ApplicationModel> Process()
{
return new ProcessorResponse<ApplicationModel>();
}
}
Models
public class ConfigurationModel
{
public int Count { get; set; }
}
public class ApplicationModel
{
public string Title { get; set; }
}
My dependency injection to add the implementations.
public static void AddGenerators(this IServiceCollection services)
{
// add our generators
services.AddScoped<GeneratorBase<ConfigurationModel>, ConfigurationGenerator>();
services.AddScoped<GeneratorBase<ApplicationModel>, ApplicationGenerator>();
}
Main App this is where my error is happening.
public class GeneratorApp
{
// error because T is not implemented
private readonly IEnumerable<GeneratorBase> _generators;
// error because T is not implemented
public GeneratorApp(IEnumerable<GeneratorBase> generators)
{
_generators = generators ?? throw new ArgumentException(nameof(generators));
}
public void RunGenerator(string name)
{
// get the generator by name and run process
var generator = _generators.FirstOrDefault(c => c.GetType().Name == name);
var results = generator.Process();
}
}
Update IFoo Example
IFoo example that works.
public interface IFoo
{
string Name { get; }
}
public class Foo1 : IFoo
{
public string Name => "I'm Foo 1";
}
public class Foo2 : IFoo
{
public string Name => "I'm Foo 2";
}
Dependency injection to add the implementations.
public static void AddGenerators(this IServiceCollection services)
{
// add our Foo's
services.AddTransient<IFoo, Foo1>();
services.AddTransient<IFoo, Foo2>();
}
Main App
public class GeneratorApp
{
private IEnumerable<IFoo> _foos;
public GeneratorApp(IEnumerable<IFoo> foos)
{
_foos = foos;
RunGenerator("Foo1");
}
public void RunGenerator(string name)
{
foreach (var foo in _foos)
{
Console.WriteLine(foo.Name);
}
var foundFoo = _foos.FirstOrDefault(c => c.GetType().Name == name);
if (foundFoo != null)
{
Console.WriteLine(foundFoo.Name);
}
}
}
Console output
I'm Foo 1
I'm Foo 2
I'm Foo 1
The basics
You're misunderstanding the purpose (and correct usage) of dependency injection.
services.AddScoped<IFoo, Foo>();
To put it into words:
If you're creating a object whose constructor needs an IFoo, please insert a Foo instance.
That is the intention of dependency injection: to provide concrete objects even though they (the class' constructors) are asking for vague types.
It allows the classes to be vague, and thus not strongly depend on any particular implementation (= concrete classes).
Your problem
Very simply put, your constructor is asking a parameter type (IEnumerable<GeneratorBase>) that you never registered.
You only registered GeneratorBase<ConfigurationModel> and GeneratorBase<ApplicationModel>, which means that your dependency injection is only able to resolve constructor parameters of those two types. Anything else, the DI framework will throw an exception as it doesn't know how to fill it in.
The solution
It seems like you want a list of all (chosen) types to be injected. Therefore, you must register this exact type. For example:
services.AddScoped<IEnumerable<GeneratorBase>>(() => new List<GeneratorBase>()
{
new ConfigurationGenerator(),
new ApplicationGenerator()
});
This is just the shortest path to workable code. However, there are still further considerations, but your intention and use case simply isn't clear. I strongly suggest reading up on dependency injection as you are missing key knowledge on how to effectively leverage it.
Footnote: You did not post a definition for GeneratorBase (non-generic) but you did reference this type. I'm going to assume that this type exists and you forgot to add it to the question. If not, then there are also some misgivings about polymorphism with generics, which I also suggest you brush up on.
Currently I have a factory class where I have method to instantiate different classes using reflection and return a base interface which all classes implement. The code works fine in general. But when I turned to write unit test (ms-test) on the class I'm running into issues when I try to instantiate multiple classes
Factory class:
public class BusinessFactory : IBusinessFactory
{
public BusinessFactory()
{
}
public IBaseBusiness Create<T>() where T : class
{
return (IBaseBusiness) Activator.CreateInstance(typeof(T));
}
}
Unit test:
I tried to stub the IBusinessFactory and inject into my class under test so I can fake the implementations that the class uses.
Example: failing to complete TestInit method, and it's failing when instantiating stub of class2.
interface IClass1 : IBaseBusiness{}
public Class1 : IClass1{}
interface IClass2 : IBaseBusiness{}
public Class2 : IClass2{}
public TestFactory{
[TestInitialize]
public void TestInit()
{
var fkBusFac = new StubIBusinessFactory();
fkBusFac.CreateOf1<Class1>(() => new StubIClass1() { });
fkBusFac.CreateOf1<Class2>(() => new StubIClass2() { });
}
Can anyone please help?
Not an answer to your question, but...
What happens if I do the following?:
var business = Create<string>();
You have absolutely no type safety at all here. If the created object implements IBaseBusiness, ensure it does and simply call new() (oh, and if its a factory method, shouldn't you be making it static?):
public static IBaseBusiness Create<T>() where T : IBaseBunsiness, new()
{
return new T();
}
public abstract class Base
{
public Base ClassReturn()
{
return this;
}
}
Is there possibility to return child type that invoked ClassReturn method?
I've done that in extension method:
public static T ClassReturn<T>(this T obj) where T : Base
{
return (T) obj.ClassReturn();
}
But I want to embeed it in Base class instead of extension method. Is there possibility to do that with generics?
I will copy my comment which describes what I want to achieve:
I need something similiar to builder pattern and I have different
classes that depending on previous operations do something else, now I
want to have a similiar functionality in every of them and when I use
it I lose object type. So my solution is either implement that
functionality multiple times in every class or create extension
method. But I always thought when it is possible to make extension
method for class then I can embeed that in class, but as I see it is
not possible.
Full example:
public class Child1 : Base
{
public Child1 Operation1()
{
Console.WriteLine("operation1");
return this;
}
}
public class Child2 : Base
{
public Child2 Operation2()
{
Console.WriteLine("operation2");
return this;
}
}
static void Main(string[] args)
{
Child1 ch = new Child1();
ch.Operation1().Operation1().ClassReturn().Operation1()
}
I can't use Operation1 after ClassReturn if I don't use extension method.
Try this one:
public abstract class Base<T> where T: Base<T>
{
public T ClassReturn
{
get { return (T)this; }
}
}
public class Child1 : Base<Child1>
{
}
public class Child2 : Base<Child2>
{
}
From your question and your comments, what you are trying to achieve is not possible directly from the type system. By returning an instance of Base you are specifically saying that all you are interested is that you have something that derives from Base, but that the specific class doesn't matter. Statically, the compiler no longer has the information it needs to perform a cast.
If you are trying to get the original type back statically, then you have to supply the information to the compiler, and in this case you can't guarantee that you have the correct information. In the example below, the instance is created from derived type A but attempted to be cast to derived type B through the extension, the compiler will allow the code to compile, but you'll get an exception at runtime.
public class A : Base { }
public class B : Base { }
public static class BaseExtensions
{
public static T GetAsT<T>(this Base base) where T: Base
{
return (T)base;
}
}
public static void Main()
{
Base obj = new A();
B b = obj.BaseAsT<B>(); // This compiles but causes an exception
}
You should look up the Liscov Substitution Principle to get information on how to properly work with base and derived classes in the system as a whole, and then write up a question dealing specifically with the result you are trying to achieve.
I want to force my child classes to pass themselves as as the generic parameter to the parent class.
For example :
class BaseClass<T> where T: BaseClass
{
//FullClassName : Tuple [Save,Update,Delete]
Dictionary<string,Tuple<delegate,delegate,delegate>> dict = new Dictionary...;
static BaseClass()
{
RegisterType();
}
private static void RegisterType()
{
Type t = typeof(T);
var props = t.GetProperties().Where(/* Read all properties with the SomeCustomAttribute */);
/* Create the delegates using expression trees and add the final tuple to the dictionary */
}
public virtual void Save()
{
delegate d = dict[t.GetType().FullName];
d.Item1(this);
}
}
class ChildClass : BaseClass<ChildClass>
{
[SomeCustomAttribute]
public int SomeID {get;set;}
[SomeCustomAttribute]
public string SomeName {get; set;}
}
public class Program
{
public static void Main(string[] args)
{
ChildClass c = new ChildClass();
c.Save();
}
}
Obviously the above code won't compile. I'll restate : I want the child class to pass itself as the generic parameter and not any other child of BaseClass.
(The above code is kind of a psuedo code and will still not compile).
You can do this:
public class BaseClass<T> where T: BaseClass<T> { }
public class ChildClass : BaseClass<ChildClass> { }
But this doesn't force you to use ChildClass as the generic parameter. You could do this public class OtherChildClass : BaseClass<ChildClass> { } which would break the "coontract" that you want to enforce.
The direct answer is that if your accessing a static method then typeof(T) will give you the type for reflection.
However, there is probably better solutions than using reflection. Options:
1) Static constructor on the child class.
2) Abstract method declared in the base class.
I do not know the application, but I get concerned about my design if I feel like using a static constructor, I also get concerned if a base class needs to initialize the child class.
I suggest looking at injection as a solution rather than inheritance. It offers superior unit testing and often a better architecture.
More info (after initial post), this is my preferred solution:
public interface IRegesterable
{
void Register();
}
public class Widget : IRegesterable
{
public void Register()
{
// do stuff
}
}
public class Class1
{
public Class1(IRegesterable widget)
{
widget.Register();
}
}
Hope this helps
The ConcurrentDictionary is being used as a Set<Type>. We can check in the Set<Type> if the type has been initialized. If not we run RegisterType on the type.
public abstract class BaseClass
{
//Concurrent Set does not exist.
private static ConcurrentDictionary<Type, bool> _registeredTypes
= new ConcurrentDictionary<Type, bool>();
protected BaseClass()
{
_registeredTypes.GetOrAdd(GetType(), RegisterType);
}
private static bool RegisterType(Type type)
{
//some code that will perform one time processing using reflections
//dummy return value
return true;
}
}
public class ChildClass : BaseClass
{
}
There are several inefficiencies with this pattern though.
object.GetType() is pretty darn slow, and inefficient.
Even with the HashSet behavior, we are checking for initialization on each instanciation. Its as fast as I can get it, but its still pretty superfluous.
public abstract class A
{
// constructors omitted
public abstract A Create(SomeData data);
}
public class B : A
{
// constructors omitted
public override A Create(SomeData data)
{
return new B(data);
}
}
What I want is to be able to make the Create method static, so that I can get an instance of B without having to create a useless instance with an empty constructor. (If you're wondering why, A is actually a generic type of the form A<TFoo, TBar>, where TBar corresponds to the derived types. As we all know, you can't instantiate a generic type using a constructor that takes any arguments.)
I am already aware that static methods are decoupled from the object hierarchy, only relying on the name of the type. That means I can't have Create as an abstract method that I force all descendants to implement. Is there another way I can implement this pattern?
Something like this might work, depends on your requirements
public abstract class A
{
public string Data { get; set; }
public static T Create<T>(string data) where T : A, new()
{
return new T() { Data = data };
}
}
public class B : A { }
then can do
A foo = A.Create<B>("foo");
There is simply no way to do this. Inheritance is based off of instance methods in C# and has no equivalent feature for static methods. Another way to implement this pattern though is to require a lambda in lieu of a static method.
For example (you mentioned the actual type was A<TFoo, TBar>)
void UseIt<TFoo, TBar>(A<TFoo, TBar> p, Func<SomeData, TBar> func) {
TBar b = func();
...
}
The consumer doesn't care if Create is static, instance or even called create. Generally all they care about is having a function which takes a SomeData and returns a TBar. Delegates fit this pattern exactly.