Currently, I am learning ASP.NET MVC 5. I am stuck at one point in the book called Dependency injection. I will try my best to learn how to use it, but before I do that I would like you to help me. I started learning C# a few weeks ago and the one thing I haven't figured out yet is the interface. I know why and when to create it, but I don't really understand when it comes to making reference variables.
Let's say I have an interface called IValueCalculator. Then I have a class LINQValueCalculator which implements IValueCalculator. Now, here comes my misunderstanding.
LINQValueCalculator referenceVariable = new LINQValueCalculator();
This will create a new instance and will be bound to use with referenceVariable.
I can then use everything that interface told me to use and any added stuff to the class.
But, what if I do this...
IValueCalculator referenceVariable = new LINQValueCalculator();
What is the difference? Can I still do the same thing as before or has something changed?
What if I had something like this
public class ShoppingCart
{
private IValueCalculator calc;
public ShoppingCart(IValueCalculator calcParam)
{
calc = calcParam;
}
This means I can put only those object's references which implement that interface right? Or am I wrong?
When I truly understand the point under all this, I will then continue learning Ninject (DI).
The underlying object is still a LINQValueCalculator but you can only refer to the IValueCalculator methods and properties while using referenceVariable because that variable is just the interface.
To make use of any of the properties of LINQValueCalculator you'll have to cast the variable. You can do this each time you need to use it:
((LINQValueCalculator)referenceVariable).SomeMethod();
or just the once:
var anotherReference = (LINQValueCalculator)referenceVariable;
Here, anotherReference and referenceVariable are references to the same object so changes to one will be reflected in the other.
Using the interface means that you can pass the object to other code that doesn't know (or need to know) about LINQValueCalculator, but acts on the properties and methods of IValueCalculator.
What is the difference? Can I still do the same thing as before or has something changed?
You can do the same things :-)
Unless if the concrete type offer more method than the interface !
This means I can put only those object's references which implement that interface right? Or am I wrong?
And you're right !
The benefits of using interface in the last case is that you can receive an object that implements IValueCalculator but you (really) don't care about the concrete type.
If you decide to create a second concrete type that implements the IValueCalculator (more performant maybe ?), you can do it and inject it into ShoppingCart constructor without change the ShoppingCart code !
Related
I am using Net Core 5 and had not yet had a need to use anything other than the built in Dependency Injection. I now have a need to be able to resolve a specific service based on the value selected from a dropdown list of services in a UI.
Out of all the DI containers out there I have decided to delve a bit further into Autofac and think that using either named services and a factory pattern or keyed services will be the way to go but I am running into a bit of difficulty, here is an example;
I have an Interface that look like this
public interface IChartDataService<TSource, TTarget>
And I have services that have to implement this interface like this
public class TreantService : IChartDataService<SourceDto, TargetDto>
I am struggling to work out how I am supposed to register these services in the Autofac container.
For named services I have tried to register like this
containerBuilder.RegisterGeneric(typeof(MarkOneService)).As(typeof(IChartDataService<,>)).Named<MarkOneService>("markone");
containerBuilder.RegisterGeneric(typeof(MarkTwoService)).As(typeof(IChartDataService<,>)).Named<MarkTwoService>("marktwo");
and I try to resolve them like this
var service = scope.ResolveNamed("markone", typeof(IChartDataService<,>));
also tried it this way
var service = scope.ResolveNamed("markone", typeof(IChartDataService<SourceDto,TargetDto>));
I cant have registered them correctly as this errors with saying that the service is not registered.
My preferred method would be to use Keyed services, that way I can make use of 'IIndex' but again this is stumping me as to how to register or whether what I am trying to do is even possible.
I am trying to register keyed services like this
containerBuilder.RegisterGeneric(typeof(MarkOneService)).As(typeof(IChartDataService<,>)).Keyed("markone", typeof(IChartDataService<,>));
OR
containerBuilder.RegisterType<MarkOneService>().As<IChartDataService<,>>().Keyed<IChartDataService<,>>("markone");
I am clearly missing something as I cant seem to get the syntax right to be able register correctly. When I do get the registration working I then cant resolve the service because of the open interface.
Also, as I would prefer to use keyed service I dont know how I would be able to get the injected service dictionary. This obviously wont work as it doesn't match my Interface
IIndex<string, IChartDataService> serviceDic
and this is syntactically invalid according to VS
IIndex<string, typeof(IChartDataService<,>)> serviceDic
OR
IIndex<string, IChartDataService<,>> serviceDic
I have spent way too much time on this now and I am going round in circles so could do with some tother insight as to where I may be going wrong, anybody any suggestions? can you point me to any examples of what I am trying to acheive please?
There's a bit to unpack here and, while I can kind of explain why things aren't working the way you want, the short answer is you're probably going to have to redesign how you're doing what you're doing. Which is likely not the answer you want, but... it's the answer.
To understand why, we need to ignore Autofac entirely for a moment and just look at the types you're working with.
You have an interface:
public interface IChartDataService<TSource, TTarget>
As an open generic, this could be IChartDataService<string, Exception> or it could be IChartDataService<object, object> or anything else. (Yes, I get there may be constraints, but stick with me - as an open generic, those types could change all over the place.) So when you talk about IChartDataService<,> in that form, that's what you're saying: "The open generic where anything could be in either of those type parameter spots."
Now, sometimes folks will create an equally generic implementation, like:
public class ChartDataService<TSource, TTarget>
: IChartDataService<TSource, TTarget>
Taking a step back to Autofac, that's what RegisterGeneric is for - to handle the open generic implementations. If you had this sort of thing, you'd register like:
builder.RegisterGeneric(typeof(ChartDataService<,>))
.As(typeof(IChartDataService<,>));
In that case, you're actually registering an open generic.
However, that's not what you have. You have types that implement an interface - a very specific interface. Let's look at what you have:
public class TreantService : IChartDataService<SourceDto, TargetDto>
Based on that, we see:
TreantService isn't a generic at all. That class, itself, has no generic type parameters.
TreantService implements a closed generic interface. Put another way, you can cast a TreantService to an IChartDataService<SourceDto, TargetDto> but you can't cast it to IChartDataService<string, Exception> or anything else.
For all intents and purposes, IChartDataService<SourceDto, TargetDto> in this case is no different than any other standard interface like IComparable or something. Once it's a closed generic like this, it's just a type.
So let's say you have a bunch of these, with a bunch of different DTO types:
public class FirstService
: IChartDataService<FirstSource, FirstTarget> { }
public class SecondService
: IChartDataService<SecondSource, SecondTarget> { }
public class ThirdService
: IChartDataService<ThirdSource, ThirdTarget> { }
Sure, they all implement IChartDataService<TSource, TTarget> but they're closed generics. You can't cast them to the same underlying interface.
Now let's say you want to store them all in a List<T>. What would the T be there to make that work?
It'd be object - the only common base class they have. You'd have to use List<object>. Which, yeah, sucks, but as you found there's no such thing as a List<IChartDataService<,>>, or a dictionary that would hold an open generic as the value. If you think about it, that makes sense, because let's say you wanted to pull them back out:
// Pretend this is a thing.
var list = new List<IChartDataService<,>>();
foreach(var item in list)
{
// What type is `item` in this loop?
// How does the compiler know what types
// to fill in for the open generic? It's
// not a dynamic language, so you can't
// "switch types" on every loop iteration.
}
Hopefully at this point you can start seeing some of the problems with what you're trying to do, and it's not a problem with Autofac - it's a problem with how the interfaces are designed and how you want to consume them.
This is why you'll sometimes see non-generic interfaces like System.IEnumerable and generic counterparts like System.Generic.IEnumerable<T>. IEnumerable for the things that are common regardless of the generic type parameters and the generic to make things strongly typed.
I can't really tell you how to solve the problem because how you approach it will largely be dependent on your application code and what exactly you're doing. But, a recap of what I've covered here is where I'd personally start if it was me:
Ignore Autofac. Try to design things that you could mock out entirely in a unit test (like having a constructor parameter with the right types that can simulate what you'll actually see). If you can't get it to compile or work with all your types without Autofac, Autofac is not going to magically somehow make it work.
Consider a common non-generic interface. Sort of like that IEnumerable vs IEnumerable<T> difference. It may be that for implementation purposes it's nice to have that generic, but the actual common methods that get called don't require the generic (or maybe could take object?).
I have an app that supports two data access layers: db4o and RavenDB. The logic classes make calls like this to get a concrete data class:
return DataAccessFactory.GetDataInterface<IApplicationData>().GetAll();
Here is the method in DataAccessFactory that returns the correct ApplicationData (db4o or RavenDB) concrete class:
public static T GetDataInterface<T>() where T : class
{
T theObject = // Code here to get the object. Not relevant to this question.
// Begin HACK
DataAccessLayerBase theObjectAsRavenDalBase = theObject as DataAccessLayerBase;
if (theObjectAsRavenDalBase != null)
{
theObjectAsRavenDalBase.SetAsInitialDalInstanceAndCreateSession();
}
// End HACK
return theObject as T;
}
The hack that I've implemented is casting to RavenDB's version of DataAccessLayerBase and that if statement. If the concrete class happens to be a RavenDB class, then I need to call a method on it. (The DataAccessLayerBase, shown here, is in the RavenDb namespace. db4o also his its own DataAccessLayerBase.)
One way to fix this would be to have each DataAccessLayerBase implement a common method, like Initialize(). The db4o Initialize() method would do nothing, and the RavenDB Initialize() method would perform the necessary logic. Then this method could simply call Initialize() and not care which concrete class it was.
Is there a better design than this? I think the fix that I just described is decent enough, but I can't help but think I'm missing something. I'm looking for a better, more elegant way to solve this. One drawback with my proposed approach is that other data access layers must then implement Initialize() even though I only needed it for RavenDB.
Note: I can't just have the concrete classes do this initialization when they're created, because it should only happen when a call is made to DataAccessFactory.GetDataInterface<>().
One other solution would be to add a type property on an interface implemented by your DataAccess classes. You could then check the type to know if you need to call the SetAsInitialDalInstanceAndCreateSession method. I think the Initialize method you describe above is a good solution too though
I know interfaces cannot define constructors. Here's what I wish I could do:
public interface SavableObject {
void Save(ObjectSaver saver);
SavableObject(ObjectLoader loader); //This, obviously, doesn't work
}
//Loading an object inside ObjectLoader:
T LoadObject<T>() where T : SavableObject {
return (T)Activator.CreateInstance(typeof(T), this);
}
And I could do this if I took out the line that didn't work, and there would just be a runtime error when trying to load (or possibly save, if I put an assert in there) the object if it didn't have the constructor. I'm just wondering if there's any way to require a class to have a particular constructor that can be used with the Activator. Can I use a custom attribute somehow, and require that attribute to be on the class? Or must I rely on runtime checks to load and save data?
I know I could have a parameterless constructor and a Load(ObjectLoader) method but I don't necessarily want to have a parameterless constructor available to abuse for other purposes.
what about ISerializable?
In brief I suggest you use generics as most factories do.
public interface SavableObject<T> : where T : new
{
void Save(IObjectSaver<T> saver);
SavableObject<T> Load(ObjectLoader loader); //This, obviously, doesn't work
}
However, you seem to have turned it on it head. The class is doing what factory must do. So I do not think it is such a good idea to pass the factory to the entity itself and that is part of the problem you are experiencing in the design.
If you are not afraid of using Reflection, like Activator that you have shown, you can do little trick I tend to use:
Make parameterless constructor that is protected
Make Load method, that is also protected (or private, I tend to use virtual protected so I support inheritance)
Create new object using this non-public constructor (through reflection - you can't create instance of your class "just like that" using new operator)
Invoke load method (also using reflection - no one will call it later).
I don't know if this will work for you, but I used that method when I needed to deserialize pretty big game state and it was pretty fast, eventhough all this reflection (for many reasons I did not wanted to use built-in serialization methods and Factory Pattern wouldn't do, so I tend to treat this method as something that may be useful if other methods fail, on the other hand, if I could - I would probably use built-in serialization for simplicity).
How about adding a property on your interface:
public interface SavableObject
{
void Save(ObjectSaver saver);
ObjectLoader ObjectLoader {get; set;}
}
Then in your factory:
T LoadObject<T>() where T : SavableObject
{
var result = (T)Activator.CreateInstance(typeof(T));
result.ObjectLoader = this;
return result;
}
Based on your question and comments.
I think you should do it at runtime using reflection.
Combining constructors and interfaces is ilogical from its core. Interface is about what concrete instance can do, not how to initialize it. This can only be achived using abstract class.
Maybe using factory to create instance of the class?
Also I don't think you can get better speed than default ISerializable implementation. Unless you are .NET GURU and have years of time for it.
Short answer: It's not possible, I guess. There are no attributes or generalizations I can use to require a specific kind of constructor on a class.
I am just learning C# and I have a problem now. :-)
In C++ I loved to use "const reference" as a parameter to avoid that
the called method changes my passed object.
I read somewhere that I can do sth. similar in C# by using Interfaces.
In the interface I would just put some "getters" to allow the method a readonly access
to my object.
Now guess, that I want to pass my C# method a built-in container like "List".
But I want to avoid that the method changes something in that list.
Just read only!
My first thought was:
- I create a new Interface called IMyOwnInterface, which uses the interface IList as well
My new interface IMyOwnInterface contains only "getters"
I change my method to sth. like that MyLittleMethod(IMyOwnInterface if)
Now the method "MyLittleMethod" can just see the "getters", which I put in my own interface and not the "setters" of IList
Is this possible?
Can someone give me a hint?
You want to use List.AsReadOnly.
http://msdn.microsoft.com/en-us/library/e78dcd75(VS.80).aspx
Yes, I believe that would work. Give it a shot, and let us know how it works :D
The answer is no:
IList does not implement IMyOwnInterface so you can't cast it.
IList list = ...
MyLittleMethod((IMyOwnInterface)list) // Compiler errror here
In this case you can use ReadOnlycollection:
IList list = ...
MyLittleMethod(new ReadOnlyCollection(list))
With interfaces, it's basically only possible through inheritance or with some proxy stuff (either explicit with an adapter class, via a RealProxy implementation, or with a library to do things like that, such as LinFu).
However, out of the box you can use delegates to do late-binding for single methods with matching signature.
I like the idea of "programming to interfaces" and avoiding the use of the "new" keyword.
However, what do I do when I have two classes that have the same interface but are fundamentally different to set up. Without going into detail about my specific code, I have an interface with a method, "DoStuff". Two classes implement this interface. One is very simple and requires no initialisation to speak of. The other has five different variables that need to be set up. When combined, they allow for literally millions of ways for the class to work when DoStuff is called.
So when do I "new" these classes? I though about using factories but I don't think they are suitable in this case because of the vast difference in setup. (BTW: there are actually about ten different classes using the interface, each allowing the formation of part of a complex pipeline and each with different configuration requirements).
I think you may be misunderstanding the concept of programming to interfaces. You always have to use the new keyword in object oriented languages to create new instances of objects. Just because you program to interfaces doesn't remove that requirement.
Programming to an interface simply means that all your concrete classes have their behavior defined in an interface instead of in the concrete class itself. So when you define the type of a variable, you define it to be the interface instead of a concrete type.
In your case, just implement DoStuff in your concrete classes as each class needs it implemented (whether doing it simply or with 10 other initialized objects and setup). For example, if you have an interface IInterface and class SomeClass which implements IInterface. You might declare an instance of SomeClass as such:
IInterface myInstance = new SomeClass();
This allows you to pass this instance around to other functions without having to have those functions worry about the implementation details of that instance's class.
Well you really have 3 options. Use new, use a factory or use an DI container. With a DI container your five variables would most likely need to be in a configuration file of some sorts.
But to be completely honest it sounds like you're making your life harder than it needs to be by forcing yourself into a corner. Instead of coding to some ideal, rather code in a manner which best facilitates solving the problem at hand. Not saying you should do a hack job of it, but really, saying you don't want to use new, that is really making your life harder than it needs to be...
Regardless of what you use, at some point you're going to have to construct instances of your classes in order to use them, there's no way around that.
How to go about doing that depends on what you want to accomplish, and the semantics of those classes.
Take the class you mention with those fields.
Can those fields be read from somewhere? A configuration file, as an example? If so, perhaps all you need is just a default constructor that initializes those fields from such a configuration file.
However, if the content of those fields really needs to be passed in from the outside world, there's no way around that.
Perhaps you should look at a IoC container and Dependency Injection?
If you are passing that many configuration parameters into your class it may have too many responsibilities. You should look into breaking it up into smaller classes that only have a single responsibility.
Avoiding the new keyword can be valuable because it creates a dependancy on the implementing class. A better solution would be to use Dependancy Injection.
for example
public interface IDoStuff
{
void DoStuff();
}
public class DoStuffService
{
private IDoStuff doer;
public DoStuffService()
{
//Class is now dependant on DoLotsOfStuff
doer = new DoLotsOfStuff(1,true, "config string");
}
}
public class DoStuffBetterService
{
private IDoStuff doer;
//inject dependancy - no longer dependant on DoLotsOfStuff
public DoStuffBetterService(IDoStuff doer)
{
this.doer = doer;
}
}
Obviously you still have to create the IDoStuff object being passed in somewhere.
An Inversion of Control (IoC) container is a good tool to help with implementing this.
Here is a good tutorial for Castle Windsor Container if you are interested in learning more. (There are many other IoC containers, I just happen to use this one.)
The example in your question was very abstract, so I hope this answer is helpful.
If I understand you correctly the problem is with different initialization. You need to provide for two classes that have the same interface. One does not need anything, and the other needs some paramaters and calls some complex initialization.
You should use have a constructor that gets InitializationParameter. Both classes should get it. One with a simple interface that does not need to get anything from it. The other that needs params and will get them from it.
If you are concerned about initialization you can use factory, just ask it for some interface providing this init parameter and factory will create, init and return to you the object according to the values you provided.
If something is not clear - please ask.