I have a 3rd party class library. One of the classes in that library, has a constructor with multiple overrides.
I want to tell Unity to create the class, using a constructor with fewer parameters (by default, it selects the one with the most number of parameters). How can I do this?
I know I can use InjectionFactory, but I prefer to let Unity create the object for me, than writing a delegate for it. Also if I had access to the source I could probably label the desired constructor with InjectionConstructor, but I don't. So what would be my other option?
Since you cannot use InjectionConstructorAttribute (as you mentioned, the library is not yours), you can use the InjectionConstructor class (not an attribute). You will need to call Resolve yourself to make sure Unity builds up the constructor parameters. Something like this:
IUnityContainer c = new UnityContainer()
.RegisterType<IStuff, GoodStuff>()
.RegisterType<StuffUser>(new InjectionConstructor(c.Resolve<IStuff>()));
Related
I want to create a custom method that will work when added after “Console” in c#. It would be sort of similar to Console.WriteLine().
It would look something like this: Console.PrintMyName(). And when it is called, it would do this: Console.WriteLine(“James”).
Is there some way to do this by defining a function that only works as a method when put after after “Console”.
In short, no.
The closest thing you can do is approximate what you want.
The Console class (System.Console specifically) is a static class and so cannot have "methods added to it" in the same way as a class that can be instantiated (instantiated classes can have extension methods).
The closest you can come to this is to either
create your own class named Console with it's own PrintMyName method. However, if you use both System.Console and your custom MyCustom.Console in the same compilation unit, you will have to disambiguate them by addressing one or both by their full namespace.
create a new static class with a completely different name.
I've got a lot of implementations of a specific generic interface and would like to resolve all of these implementations in the constructor. Of course, I can just add every implementation in the constructor. This will cause the constructor to have over 30 parameters, which isn't very nice to look and develop at.
While doing some research on the matter I discovered it's possible to inject an IEnumerable of an interface in the constructor, somewhat like this IEnumerable<IScriptExecution> scriptExecutionImplementations
This is what I'm searching for, but I need it to be like so:
public TheConstructor(IEnumerable<IScriptExecution<T>> scriptExecutionImplementations)
{}
Is it possible to inject all the IScriptExecution<T> in the constructor, using Autofac?
The following is an excerpt from my registration class:
builder.RegisterType<Library.ShardManager.Execution.DataScript.Users>().As<IScriptExecution<DBUser>>();
builder.RegisterType<Library.ShardManager.Execution.DataScript.Companies>().As<IScriptExecution<DBCompany>>();
Note: I don't think I need to use the Open Generics, because I already know the types and you can't use open generics in a constructor.
As requested by Jim Bolla in the comment section, an example on how I want to use this.
At the moment I've got this constructor:
public MoveShardletData(Guid shardletId, ShardLocation oldLocation, ShardLocation newLocation, ILog log,
IScriptCreator<DBAnalyticsInvitation> scriptAnalyticsInvitation, IScriptCreator<DBAnalyticsPromotion> scriptAnalyticsPromotion,
IScriptCreator<DBAnalyticsRetailerSubscriptionModule> scriptAnalyticsRetailerSubscriptionModule, IScriptCreator<DBAnalyticsRetailerSubscription> scriptAnalyticsRetailerSubscription, //and the list goes on...
The piece of code where I want to use the IScriptCreator<T> objects looks a bit like this:
var analyticsInvitations = GetTheAnalyticsInvitationObjects(someLocalVariableInTheCurrentScope)
var script = scriptAnalyticsInvitation.Insert(analyticsInvitations);
sb.Append(script);
//With all IScriptCreator<T> objects listed here in the same fashion.
It would be nice if this could be done in a loop. Because of the someLocalVariableInTheCurrentScope it's a bit hard to extract this piece of code.
The collection analyticsInvitations is the type T. If I can access the Autofac container I can probably resolve the correct IScriptCreator<T> manually, but that's cheating thus not advised.
I am using .NET (MVC5, Web API etc). I understand constructor injection just about (fairly new to using it in anger).
I have a class with a method that has a dependency. I don't want to use constructor injection because then I will be creating the dependent object every time this class is instantiated (and most of the methods don't use this dependent object).
So I thought method injection sounded like it might be the thing. However I can't figure out how to do it (I am using Autofac).
So if my method is
void DoSomething(string x, int y)
and that method needs to use an implementation of IMyService, how do I do this without using the constructor injection?
The only method injection technique I have seen is one where effectively a method is called at instantiation. This doesn't seem to help my case, it still means that all instances create this dependency even if I am going to call a method that doesn't need it.
I'm sure it is something simple but I can't figure it out right now. Could you help me with an example please?
UPDATE
this is the crux of it. I like the idea of Lazy suggested by Jim and will try this. So is method injection as I suspected and if so I don't really understand the point of it - why use it instead of constructor injection?
public class MailService {
// lots of methods that don't need PlayerDataService
public void SendPlayersEmail() {
var service = new PlayerDataService();
var players = service.GetPlayers();
foreach(var player in players) {
SendEmail(player);
}
}
}
I don't want to use constructor injection because then I will be creating the dependent object every time this class is instantiated (and most of the methods don't use this dependent object).
There's the problem. Break that functionality out into a new class.
That is, at least in my experience, the best solution when a method does not fit into the rest of the class (or have dependencies that are not used anywhere else).
You should also consider that object allocation is pretty cheap, you need millions of allocations per second before the performance is hurt (unless you are using Ninject ;))
If the cost of instantiating your object during construction is an issue, you can wrap it in a Lazy<> to avoid unnecessary construction. This will cause your dependency to be constructed on the first call to the lazy's .Value.
I had to build a logging dll assembly that will use a large amount of optional parameters, around 20 of them. It was written in c#.
What I end up doing was let my logging class to accept an object of type "log". This "log" class contains all the needed parameters and the corresponding properties to Get/Set them.
All of the parameters were of course initiated with default values first.
Once passing the "log" object to my main logging class, it then extract the values from that "log" object and perform the printing to file.
My question is - should I change it now to the builder pattern? (I just now learn it in - "Effective Java 2nd edition" book).
I can see the advantages of this pattern against calling Ctr/Methods with a billion parameters but I also think that passing in a new object that contains all parameters is not bad.
Can you explain if I really should change my design and why?
Since this is a design question I did not provide any code input. If I need to post some code let me know.
There is no compulsary rules for using design pattern. But it makes life simpler if applied to correct usecase.
You can definitely use Builder pattern in your case. Here are some guidelines:
First decide how many of the attributes of the Log object are mandatory (say x number), and how many of the attributes are optional (y).
2.Remove the y attributes from log object and put that in your Builder class through "add" methods.
If x<6 , remove the x attributes from log class, put them in the constructor of your Builder class. Now you can get rid of the Log class itself.
Else, if x>=6, keep them in the log class and pass the class in the constructor of your Builder class. This is also called "Transfer Object".
you can change the deciding number 6 as you wish. Usually a constructor containing 6 or more paramters becomes less readable.
Do you have a constructor with many arguments, where many of them are of the same type? Go Builder.
Do you have many constructors, where the difference between them is minimal? Go Builder.
Do you have a class initialized where one constructor calls another constructor, following a chain-like structure? Go Builder.
Otherwise, do your own thing.
I'm using C# and Unity Dependency Injection for developing a MVVM application in WPF. I'm looking for a cleanest solution for a following problem.
Some of my classes are parametrized with enums, for example, I have a class AudioChannelViewModel (let's call it for short A) and I want to register two instances of the class, one for Channel.Left and one for Channel.Right. This alone is not a problem, because I register those instances by naming them in RegisterType and then referring to them later by [Dependency(name)] attribute.
Moreover, A depends on some other classes, lets call them Dep1, Dep2 and Dep3. To perform the initialization of A, I must have ALL of my dependencies and the information about the Channel.
I tried to use the following strategies:
Property injection of Dep1, Dep2 and Dep3 and setting A's Channel in constructor by RegisterType with InjectionConstructor parameter. But how should I know when A is ready to be initialized? AFAIK I cannot assume anything about the property injection order.
Constructor injection of all four items. It would be IMHO the cleanest solution, as I would be able to perform initialization in constructor. But I'm unable to get this working in Unity. Registering A with InjectionConstructor param for Channel throws an exception, and registering with four InjectionConstructor params seems ugly.
Constructor injection of Dep1, Dep2 and Dep3 and property injection of Channel. Then I can initialize my class in the Channel setter. It works for this case, but what if A would be parametrized by more than one property? Then I wouldn't know when A is fully built up and ready for initialization.
How should the initialization be performed? Or maybe I'm making things overly complicated.
You don't say exactly what the exception was that you observed in strategy #2, but this is the approach I would be using (given your other requirements for being able to other initialisation having had all the dependencies successfully resolved). I suspect the problem is that you aren't providing a 'value' for all of the arguments of the constructor... InjectionConstructor assumes the constructor you want is the one matching the types of the values provided to the InjectionConstructor.
E.g. if you want to register a constructor for such a class...
public class AudioChannelViewModel {
public AudioChannelViewModel(Channel channel, Dep1 dep1, Dep2 dep2, Dep3 dep3) {
...
}
}
You should register it thus...
container.RegisterType<AudioChannelViewModel>("left",
new InjectionConstructor(Channel.Left,
typeof(Dep1), typeof(Dep2), typeof(Dep3)));
container.RegisterType<AudioChannelViewModel>("right",
new InjectionConstructor(Channel.Right,
typeof(Dep1), typeof(Dep2), typeof(Dep3)));
Unity will use the provided value for the first argument (a Channel enum value) and will then resolve the Dep1, Dep2 and Dep3 instances. You can also use ResolvedParameter<T> as an argument to InjectionConstructor if there were specific named instances of Dep1, Dep2 or Dep3 that you require.
Just providing Channel.Left or Channel.Right alone is insufficient, as Unity will believe it is being asked to use a constructor with just a Channel argument.
Or; if you HAVE already tried that and it isn't working... maybe Unity doesn't support enums in this instance (pun intended).
This MSDN page might shine some more light on the issue.