My program have two classes; both derive from same base class.
class A : MyBase
{
internal A(InitVal initVal)
}
class B : MyBase
{
internal B(InitVal initVal)
}
InitVal is another class which is injected through constructor. This class is for internal usage. Due to internal constructor, user cannot create instance of class A and B directly. Instead, I created method which creates these objects.
class Initiator
{
InitVal initVal;
public T CreateObject<T>(ObjectInstance objectInstance) where T : MyBase
{
MyBase myBase = null;
switch(objectInstance)
{
case ObjectInstance.A:
myBase = new A(initVal);
break;
case ObjectInstance.B:
myBase = new B(initVal);
break;
}
return (T)myBase;
}
...
}
ObjectInstance is enum in above code.
This works without problem but I am sure you have never seen such ugly code earlier.
Please suggest creational pattern I should use. I want to remove ObjectInstance enum without changing functionality. It will cleanup much.
I tried Creational Patterns mentioned on dotfactory.
Factory Method and Abstract Factory does not look proper in this case.
My code even though look ugly, it is very simple to read and understand. I tried implementing patterns mentioned above which increases code complexity. So this is also my criteria while choosing answer.
I cannot change anything in code except Initiator class. All other classes are not accessible to me for edit.
Edit 1: Why above code is ugly in my view
1) While calling CreateObject method, user have to specify type of the object twice.
A a = initiator.CreateObject<A>(ObjectInstance.A);
First for T generic value and second to enum value.
I want to avoid this.
2) As user has to specify type of object twice, there are chances of mistake.
A a = initiator.CreateObject<A>(ObjectInstance.B);
In above code, enum value and generic value are different.
This is not allowed and will be a problem.
With my code, I cannot avoid this.
That is why; I am looking for pattern that suits my case without increasing complexity.
If I remove necessity of enum somehow, code will be lot better.
If I can change signature of CreateObject to following, it will be lot better.
public T CreateObject<T>() where T : MyBase
But, I am not sure how I will implement this method to create proper instances.
It doesn't look to me like you are getting any advantage from trying to make this generic. You needs to know the concrete type of the returned value at the call site.
Therefore why not keep things simple and just do this?
public class Initiator
{
InitVal initVal;
public A CreateA()
{
return new A(initVal);
}
public B CreateB()
{
return new B(initVal);
}
}
As you specified the method as generic one, I expect you might actually know the type you want to get already during the compilation time.. so I'd go for something like this:
class Initiator
{
public T CreateObject<T>(ObjectInstance objectInstance) where T : MyBase, new()
{
T newInstance = new T();
newInstance.Value = initVal;
return newInstance;
}
...
}
now you can call it as:
A myAInstance = initiator.CreateObject<A>();
MyBase myAInstance = initiator.CreateObject<A>(); //this also works
To make it work you need to specify an internal parameterless constructor in your classes and specify interface for the Value property or whatever you would set now in your current constructor.
class MyBase{
InitVal Value { get; set;} //this allows construction of the object with parameterless constructor
...
}
This is not only cleaner and shorter, but also less error prone, as you dont need to edit both enum and method body every time new type is added. It gives less flexibility for child-type specific logic, though.
NOTE: If you really want to have constructor with parameters as you have now you still can go for this approach but you'd need to use reflection (check Activator) or lambdas.
Of course this makes only sense if you can decide on the type during compilation time or you if you just want to delegate this decition to a 3rd party library, eg:
switch(chosenType){
case ObjectInstance.A:
instance = initiator.CreateObject<A>();
...
Otherwise, simply leave it as it is, its a FactoryMethod pattern more or less and it does the job. Just that the generic parameter in it... seems to be quite useless then. I would remove it and change return type to MyBase, as user won't be able to specify T anyway.
One last option is to simply create a separate method for each type, this is clean, flexible, gives a lot of options for customization, but sucks if you need to repeat a lot of shared logic and you need to add a new one for each next type. Simply:
A CreateObjectA(InitVal initValue){
return new A(initValue);
}
B CreateObjectB(InitVal initValue){ ...
One obvious problem with your code is the enum, which is unnecessary, because typeof(T) already gives you the appropriate type:
class Initiator
{
readonly Dictionary<Type, Func<MyBase>> _dict = new Dictionary<Type, Func<MyBase>>();
internal Initiator(InitVal initVal)
{
// initialize your "service locator".
// it's cool that different types can have different constructors,
// and people who call CreateObject don't need to know this.
_dict[typeof(A)] = (Func<MyBase>)(() => new A(initVal));
_dict[typeof(B)] = (Func<MyBase>)(() => new B(initVal, someOtherStuff));
}
public T CreateObject<T>() where T : MyBase
{
var ctor = _dict[typeof(T)];
return (T)ctor();
}
}
Alternatively, if you don't know the type, you can pass the enum, but then the return type should be an interface/base class (preferably interface):
// this is more likely, you probably don't need a generic method
public IMyBase CreateObject(ObjectInstance objectInstance)
{
// the dictionary would map enum value to Func<IMyBase>, of course
var ctor = _dict[objectInstance];
return ctor();
}
And now you have a simple "poor man's" DI class called Initiator, so I wonder if your DI framework (the one which injected InitVal) can also inject A and B instances. Which is probably true, since DI purists will tell you there is no place for factories and the new keyword in your code.
Btw, ObjectInstance is a really, really bad name for an enum.
I did it in following way:
class A : IMyType
{
internal A(InitVal initVal)
}
class B : IMyType
{
internal B(InitVal initVal)
}
class Initiator
{
InitVal initVal = .....;
public T CreateObject<T>() where T : IMyType
{
IMyType myType = null;
if(typeof(T) == typeof(A))
myType = new A(initVal);
else if(typeof(T) == typeof(B))
myType = new B(initVal);
else
throw new MyException("Type is not configured.");
return (T)myType;
}
...
}
This resolves the problems I mentioned in my question. But, it creates new problem. This violates open-close principle of SOLID. Last else block handles the manual mistake if any. Anyway, it just works for my specific case; not recommended generally.
Related
I've tried to explain my admittedly complex problem to the best of my abilities. Let me know if there is anything I can add to clarify.
A brief background
I have a DbWrapperCollection I use to store DbWrapper<TInput. TOutput> (since TInput and TOutput will vary, the collection is really just a list of non-generic “containers” containing the generic as an object as well as the input and out as System.Types – see my implementation below)
On the other hand, I have a variable number of services, all with their own IDbWrapperCollection that I want to inject with autofac at startup.
Essentially what I want to do is this:
builder.RegisterType<SaveApplDbWrapper>().As<DbWrapper<AppleDto, SavedAppleDbEntity>>()
.Named<string>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>().As<IUcHandler<OrangeDto, OrangeDbEntity>>()
.Named<string>("fruitService");
builder.RegisterType<SaveMelon>().As<IUcHandler<MelonDto, MelonDbEntity>>()
.Named<string>("appleService");
builder.Register(c => new FruitService(c.ResolveNamed("appleService")))
.As<IDbMapperService>();
My problem
As you can see above, I specifically left out the expected type parameters when calling ResolveNamed(). That’s because I, being new to autofac (and to some extent, generics), I specifically don’t know if there are any strategies to inject a list of open generic DbWrappers and defer closing of my generic type.
I will try to explain which strategies i've researched for dealing with this below, as well as my implementation so far
My own research
The way I see it, I could either create a non-generic baseclass for my wrappers and save them as that baseclass, delegating the responsibility of resolving the original generic type to that baseclass, or ditch my wrapper collection idea in favor of specific parameters on my service constructor (boring – and not compatible with my composite-inspired implementation).
With the popularity of composite pattern, I’d imagine I’m not the first person with a composite-pattern-like solution with “generic leafs” wanting to use DI and an IoC.
I’m planning to use my fruitService like this:
myFruitService.GetDbMapper<MyFruitDto, DbEntityForThatSaidFruit(myOrange);
The service looks in it’s DbMapperCollection, finds the mapper with the provided type arguments, and call its implementation of Save();
Implementation so far
For those curious, here is my implementations:
DbWrappers:
class SaveApplebWrapper : DbWrapper<TInput, TOutput>
// and plenty more wrapppers for any fruit imaginable
Service:
public abstract class DbMapperService : IDbMapperService
{
public IWrapperCollection Wrappers { get; set; }
protected BestandService(IWrapperCollection wrappers)
{
Wrappers = wrappers;
}
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
return Wrappers.GetWrapper<TInput, TResult>();
}
}
My WrapperCollection helper classes:
public struct WrapperKey
{
public static WrapperKey NewWrapperKey <TInput, TResult>()
{
return new WrapperKey { InputType = typeof(TInput), ResultType = typeof(TResult) };
}
public Type InputType { get; set; }
public Type ResultType { get; set; }
}
public struct WrapperContainer
{
public WrapperContainer(object wrapper) : this()
{
Wrapper= wrapper;
}
public object Wrapper{ get; set; }
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
return Wrapper as DbWrapper<TInput, TResult>;
}
}
And my WrapperCollection:
public class UcWrapperCollection : Dictionary<WrapperKey, WrapperContainer>,
IDbWrapperCollection
{
public void AddWrapper<TInput, TResult>(UcHandler<TInput, TResult> handler)
{
Add(WrapperKey.NewWrapperKey<TInput, TResult>(), new WrapperContainer(handler));
}
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
var key = WrapperKey.NewWrapperKey<TInput, TResult>();
return this[key].GetWrapper<TInput, TResult>();
}
}
Questions I've looked at without luck
Some questions I've looked at, none of which seemed relevant to my case (although my problem could potentially be solved with a generic delegate, I don't think it's a very optimal solution for my problem.
Injecting Generic type parameters with Autofac
Autofac. How to inject a open Generic Delegate in constructor
How to inject a factory of generic types with Autofac
Autofac with nested open generics
I don't think you're going to be able to do what you want. Sorry, probably not the answer you'd like. I'll show you why, and maybe some workarounds, but having an arbitrary collection of closed generics that don't get closed until resolution isn't really a thing.
Let's ignore DI for a second and just consider FruitService, which I don't see in the question, but which we see in a usage here:
builder.Register(c => new FruitService(c.ResolveNamed("appleService")))
.As<IDbMapperService>();
Note we can see that FruitService implements IDbMapperService because it's registered as that interface.
Further, we can see FruitService looks like it should take some sort of collection of things, since there are two things named the same in the registration example.
builder.RegisterType<SaveApplDbWrapper>().As<DbWrapper<AppleDto, SavedAppleDbEntity>>()
.Named<string>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>().As<IUcHandler<OrangeDto, OrangeDbEntity>>()
.Named<string>("fruitService");
I noticed that these both implement different generic types. I have to assume based on the rest of the question that these have no common base class.
To make it more concrete and get past the Autofac part, which I don't think is really relevant to the larger issue, let's consider it like this:
var wrapper = new[] { CreateWrapper("appleService"), CreateHandler("appleService") };
var service = new FruitService(wrapper);
Let's assume CreateWrapper and CreateHandler both take a string and, magically, creates the appropriate wrapper/handler types. Doesn't matter how it happens.
There are two things to consider here that relate closely:
What is the type of the parameter in the FruitService constructor?
What do you expect CreateWrapper("appleService") and CreateHandler("appleService") to return?
There are basically only two options here I can see.
Option 1: Use object.
If there's no common base class, then everything has to be object.
public class FruitService : IDBMapperService
{
private readonly IEnumerable<object> _wrappers;
public FruitService(IEnumerable<object>wrapper)
{
this._wrapper = wrapper;
}
public object GetWrapper<TInput, TResult>()
{
object foundWrapper = null;
// Search through the collection using a lot of reflection
// to find the right wrapper, then
return foundWrapper;
}
}
It's not clear that DbWrapper<TInput, TResult> can be cast to IUcHandler<TInput, TResult> so you can't even rely on that. There's no commonality.
But let's say there is common base class.
Option 2: Use the common base class
It seems there's already a notion of DbWrapper<TInput, TResult>. It's important to note that even if you have that generic defined, once you close it, they're two different types. DbWrapper<AppleDto, SavedAppleDbEntity> is not castable to DbWrapper<OrangeDto, SavedOrangeDbEntity>. Generics are more like "class templates" than base classes. They're not the same thing.
You can't, for example, do:
var collection = new DbWrapper<,>[]
{
new DbWrapper<AppleDto, SavedAppleDbEntity>(),
new DbWrapper<OrangeDto, SavedOrangeDbEntity>()
};
However, if you have a common interface or base class, you can do...
var collection = new IDbWrapper[]
{
new DbWrapper<AppleDto, SavedAppleDbEntity>(),
new DbWrapper<OrangeDto, SavedOrangeDbEntity>()
};
But that'd mean you can switch to that and, ostensibly, use the common interface.
public class FruitService : IDBMapperService
{
private readonly IEnumerable<object> _wrappers;
public FruitService(IEnumerable<object>wrapper)
{
this._wrapper = wrapper;
}
public IDbWrapper GetWrapper<TInput, TResult>()
{
IDbWrapper foundWrapper = null;
// Search through the collection using a lot of reflection
// to find the right wrapper, then
return foundWrapper;
// IDbWrapper could expose those `TInput` and `TResult`
// types as properties on the interface, so the reflection
// could be super simple and way more straight LINQ.
}
}
Your consuming code could just take IDbWrapper and call non-generic methods to get things done.
Bringing it back to Autofac...
Remember I mentioned the key was in figuring out what the Create methods should return; or what the FruitService constructor expects? That. That in spades.
You could register everything as keyed objects.
builder.RegisterType<SaveApplDbWrapper>()
.Named<object>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>()
.Named<object>("fruitService");
builder.RegisterType<SaveMelon>()
.Named<object>("appleService");
builder
.Register(c => new FruitService(c.ResolveNamed<IEnumerable<object>>("appleService")))
.As<IDbMapperService>();
The Resolve operations in Autofac are the create methods from my example. There's no magic there; it's just creating objects. You still have to know what type you want it to provide.
Or you could use a common base class.
builder.RegisterType<SaveApplDbWrapper>()
.Named<IDbWrapper>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>()
.Named<IDbWrapper>("fruitService");
builder.RegisterType<SaveMelon>()
.Named<IDbWrapper>("appleService");
builder
.Register(c => new FruitService(c.ResolveNamed<IEnumerable<IDbWrapper>>("appleService")))
.As<IDbMapperService>();
If you don't mind mixing the DI system into the FruitService you can do something like this:
public class FruitService
{
private readonly ILifetimeScope _scope;
public FruitService(ILifetimeScope scope)
{
this._scope = scope;
}
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
var type = typeof(DbWrapper<TInput, TResult>);
var wrapper = this._lifetimeScope.Resolve(type);
return wrapper;
}
}
You'd have to register things without them being named and As a DbWrapper, but it'd work if everything is based on that.
builder.RegisterType<SaveApplDbWrapper>()
.As<DbWrapper<AppleDto, SavedAppleDbEntity>>();
// Must be DbWrapper, can also be other things...
builder.RegisterType<SaveOrangeDbWrapper>()
.As<IUcHandler<OrangeDto, OrangeDbEntity>>()
.As<DbWrapper<OrangeDto, OrangeDbEntity>>();
builder.RegisterType<SaveMelon>()
.As<DbWrapper<MelonDto, MelonDbEntity>>()
.As<IUcHandler<MelonDto, MelonDbEntity>>();
builder.RegisterType<FruitService>()
.As<IDbMapperService>();
When you resolve IDbMapperService the FruitService constructor will get a reference to the lifetime scope from which it was resolved. All of the wrappers will be resolved from that same scope.
Folks generally don't like mixing IoC references into their code like this, but it's the only way I can see you'd get away from having to mess with reflection or casting up and down all over.
Good luck!
What is a good (object oriented) way of setting a property of a class which implements an interface, when that property doesn't always exist in all classes that implement that same interface?
e.g.
Let's say I have an interface
public interface IDataRepository {
public DataStructure GetData(); // DataStructure is an arbitrary class, doesn't matter for this example
}
Now I also have two classes that inherit from this
public class DatabaseRepository : IDataRepository {
public DataStructure GetData()
{
// get data from database
}
}
and
public class FileRepository : IDataRepository {
public string WorkingFolder { get; set; }
public DataStructure GetData() {
// get data from files
}
}
Now my client method doesn't necessarily know what the repository is but here's what I want to do...
private DataStructure ReadData(IDataRepository repository)
{
repository.WorkingFolder = #"C:\Data"; // What is the best way of doing this?
return repository.GetData();
}
obviously the above code won't work and I could do...
if (repository is FileRepository) {
((FileRepository)repository).WorkingFolder = #"C:\Data";
}
or add WorkingFolder as a property of the interface (and therefore all the classes that implement it) even though in most cases it's irrelevant.
but both of these (esp. the first one) seem very inelegant and not very object oriented. What is the oop way of doing this kind of thing?
Edit
The obvious question is if the method doesn't know what repository is, how can it know the correct value for WorkingFolder... But the above is an over-simplification of what I'm trying to do, so let's just say it can find out...
Apparently your ReadData method can't actually accept any type of repository. It is only able to handle a FileRepository. That's what it expects, and that's what it needs to do its job. Given that, that's what it should actually accept as its parameter, rather than an interface that doesn't actually provide a contract that is sufficient for it to do its job.
The entire point of having an interface is so that anyone using that interface can use it without caring what the implementation is. So if you do want to use the interface you need to include enough information in the interface's definition such that it provides every operation that anyone using the interface needs, otherwise you're better off just not using it at all (at least for that specific operation).
As for the specific example given, you should probably just be providing an already configured repository, that has whatever values it needs in order to allow this method to do its work, as a parameter. It doesn't make sense for a method that's reading a value from an arbitrary repository to be configuring that repository at all. That is, if it really is reading something from an arbitrary repository.
As others have said in the comments, you should initialise these properties in the constructor. This is where you know what type you're creating, so you also know what arguments its constructor requires / can set those there.
Once you've initialised the object, you can just pass it around / have anything using that class operate against its interface.
Example:
public void Main(string[] args)
{
var myRepo = new FileRepository(args[0]); //Here's where we set the working directory
var myThing = new Thing();
var data = myThing.ReadData(myRepo);// of course, the current implementation means you could just call `myRepo.GetData()` directly, since ReadData just passes out the same response; but presumably that method adds some additional value..
Console.WriteLine(data.ToString());
}
Supporting Code
public class DatabaseRepository : IDataRepository {
DbConnection connection; //you may want a connection string or something else; going with this type just to illustrate that this constructor uses a different type to the FileRepo's
public DatabaseRepository(DbConnection connection)
{
this.connection = connection;
}
public DataStructure GetData()
{
// get data from database
}
}
public class FileRepository : IDataRepository {
public string WorkingFolder { get; set; } //Do you need set? Generally best to keep it constant after initialisation unless there's good reason to change it
public FileRepository (string workingFolder)
{
this.WorkingFolder = workingFolder;
}
public DataStructure GetData() {
// get data from files
}
}
How do I call the code that creates the class
i.e. maybe you've implemented a really basic factory pattern like so, and want to know how to provide arguments:
public class DataRepositoryFactory
{
Type baseType = typeof(IDataRepository);
IDictionary<string, Type> typeMap = new Dictionary<string, Type>() {
{"File", typeof(FileRepository) }
,{"Db", typeof(DatabaseRepository) }
}
public void RegisterType(string typeName, Type type)
{
if (!baseType.IsAssignableFrom(type)) throw new ArgumentException(nameof(type));
typeMap.Add(typeName, type);
}
public IDataRepository GetDataRepository(string typeName)
{
return (IDataRepository)Activator.CreateInstance(typeMap[typeName]);
}
}
(For a more complex example of a factory, see https://web.archive.org/web/20140414013728/http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c).
I.e. in this scenario, when you call the factory you know what type you want, but you're only giving it a string to name/identify that class. You could add a params object[] args to your GetDataRepository method, allowing you to call it like so:
var myRepo = myDataRepositoryFactory.GetDataRepository("File", "c:\somewhere\something.dat");
That's a good approach / is actually what's used on the linked example above. However, it means that your call to this code differs for different types; since if we use variables instead of hardcoded values as in the above example we can't simply do the below, since myRepoType could be set to "Db", whilst "myFilePath" would be a string:
var myRepo = myDataRepositoryFactory.GetDataRepository(myRepoType, myFilePath);
That's fixable by calling:
var myRepo = myDataRepositoryFactory.GetDataRepository(myRepoType, myArgs);
i.e. where myArgs is an object[], giving all of the values required in the desired order to initialise the type. The piece to populate object[] with the required values could then take place at the same point at which you decided you wanted the type to be a file repo vs database repo. However, this approach isn't that clean / casting to and from objects stops you from getting help from the compiler.
So how do I improve things?
There are a few options. One is to replace the need to use object[] by instead creating a type to hold your arguments. e.g.
public interface IDataRepositoryConfiguration
{
//nothing required; this is just so we've got a common base class
}
public class FileRepositoryConfiguration: IDataRepositoryConfiguration
{
public string WorkingFolder {get;set;}
}
public class FileRepository : IDataRepository {
public FileRepository (IDataRepositoryConfiguration configuration)
{
var config = configuration as FileRepositoryConfiguration;
if (config == null) throw new ArgumentException(nameof(configuration)); //improve by having different errors for null config vs config of unsupported type
this.WorkingFolder = config.WorkingFolder;
}
//...
}
This still has some issues; i.e. we may pass a DatabaseRepositoryConfiguration as our IRepositoryConfiguration when creating a FileRepository, in which case we'd get the AgumentNullException at runtime; but this does avoid issues should parameters change order, and makes it less of a headache to code / debug.
Could it be further improved?
Dependency Injection offers one solution. This could be used along the lines of the code below (i.e. you create instances of each of your classes, providing the required arguments, and give each instance a name, so that you can later fetch that instantiation. Exactly what that code looks like would depend on the dependency injection library you used:
//setting up your repositories
var container = new Container();
container.Configure(config =>
{
// Register stuff in container, using the StructureMap APIs...
config.For<IDataRepository>().Add(new FileRepository("\\server\share\customers")).Named("customers");
config.For<IDataRepository>().Add(new FileRepository("\\server\share\invoices")).Named("invoices");
config.For<IDataRepository>().Add(new DatabaseRepository(new DbConnection(configurationString))).Named("persist");
config.For<IDataRepository>().Use("persist"); // Optionally set a default
config.Populate(services);
});
//then later when you need to use it...
public DataStructure ImportCustomers(IContainer container)
{
var customerRepo = container.GetInstance<IDataRepository>("customers");
return customerRepo.GetData();
}
I'm sure there are many other approaches, and exactly what approach to use depends on how your program will operate. Hopefully the above is enough to get you past your current problem; but if you find you're still struggling please post a new question with more detail / saying where you're still having issues having considered these points.
If possible, I'd just put the value for that property in the constructor or create a subinterface, like others suggested.
If it's not possible, C# 7.X (don't remember the exact minor version) has a nice code structure for conditional casting:
IDataRepository repo = new FileRepository();
if (repo is FileRepository fileRepo)
{
fileRepo.WorkingFolder = "some dir";
}
However in your case, you should probably rethink your architecture and always pass (or even better always create) a repository object which is ready to be used.
a) Put it into the Inferface definitions. Deal with any "NotImplemented" Exceptions. You always have to expect those with Interfaces anyway.
For example, IEnumerable has a Reset() function. But in most cases it is not implemented. It is not even supposed to be implemented in most cases. Afaik it is only there for Backwards Compatabilty with some old COM stuff.
b) make a sub-interface just for the property
c) Verify the Interface is properly implemented via is checks (throw exceptions thows if nessesary, like Array.Sort will throw a InvalidOperation one), generic constraints, proper argument types and the like.
I'm having a generic function that returns a new instance of a subclass of AnyListVM implemented basically like this:
public TListVM MakeListVM<TListVM>()
where TListVM : AnyListVM
{
TListVM listVM;
switch(typeof(TListVM).ToString())
{
case nameof(EventListVM):
listVM = new EventListVM();
// some more init stuff
break;
// some more similar cases
default:
throw new NotImplementedException();
}
return listVM;
}
The two involved classes look currently like that, without any meaningful implementation yet:
public abstract class AnyListVM
{
}
public class EventListVM : AnyListVM
{
}
Now Visual Studio underlines my new EventListVM() and nags that it can't implicitly convert EventListVM to TListVM.
Okay, so I thought I simply add an explicit cast:
listVM = (TListVM)new EventListVM();
But nope. Now Visual Studio underlines it again and says that it's a redundant cast. The offered automatic fix would be to remove the cast again. Infinite loop.
What is going wrong here, why am I not allowed to do this cast, explicitly or implicitly?
There's one glaring thing in your implementation that is incorrect, which other's have pointed out but haven't addressed satisfactorily. If you intend to instantiate TListVM, then you need to change two very important parts. First the new code listing:
public TListVM MakeListVM<TListVM>()
where TListVM : AnyListVM, new()
{
TListVM listVM = new TListVM();
EventListVM evtList = listVM as EventListVM;
if (evtList != null)
{
// set evtList properties. You can't change
// the instantiation method.
}
// repeat for other constructs.
return listVM;
}
Now, to expound a bit. The generic where clause needs to specify that you intend to create the TListVM with a parameterless constructor. To do that, you need to specify new() as a generic constraint.
This greatly simplifies your implementation which only knows there is something called TListVM that has a base class of AnyListVM and has a constructor with no parameters. There's no need for a complicated switch statement, or using the Activator.
Any time you are dealing with generics, work with your generic parameter directly.
Based on further information, the switch statement is still the wrong tool. Generics necessarily constrain how you work with your object. You can't change the constructor, but you can specialize how you set properties after the object is instantiated.
Above I changed the listing to show how to set those properties directly.
If, instead you were dead set on having different constructors, etc. then you would have to approach it differently. You would have to return the base class and not TListVM.
public AnyListVM MakeListVM<TListVM>()
where TListVM : AnyListVM
{
return MakeListVM(typeof(TListVM)) as TListVM;
}
private AnyListVM MakeListVM(Type listVM)
{
AnyListVM listVM;
switch(listVM.ToString())
{
case nameof(EventListVM):
listVM = new EventListVM();
// some more init stuff
break;
// some more similar cases
default:
throw new NotImplementedException();
}
return listVM;
}
The generic helper method lets you wrap your more generic factory method so it has the signature you want, without causing compile errors.
You can't guarantee that EventListVM will convert to TListVM as according to your generic restriction, one is allowed to pass ANY inherited class of AnyListVM, which may or may not be EventListVM. Example, if the caller of this method did this:
AnyListVM vm = MakeListVM<SomeOtherListVMConcrete>();
It would fail, but shouldn't.
I believe what you really want is to cast your EventListVM to AnyListVM, the actual base type rather than the generic.
AnyListVM listVM = new EventListVM();
Still, if you are always returning an instance of EventListVM, I'd consider removing the generic clause all together and updating the signature to have a return type of EventListVM.
To make your problem more obvious, consider a base class and two children:
public class Base { } //AnyListVM
public class Child1 : Base{ } //EventListVM
public class Child2 : Base{ } //OtherListVM
now your method looks like:
public T Get<T>() where T : Base
{
//code
T item = new Child1();
//more code
}
Imagine I send in Child2, which is perfectly valid from the method signature. The method's code now looks like:
Child2 item = new Child1();
which of course is going to be invalid at compile time.
My example below involves 2 NET classes which both contain the method CommonMethod. I would like to design MyMethod that can accept either class (Using ) while retaining the functionality common to NetClassA and NetClassB. Case1 would do just that only it is illegal as stated below. Case2 would also accomplish the goal except INetClassA and INetClassB do not exist. Therefore my question is there a way to impose a custom interface (ICommonNetMethods) on existing .NET types (Case 3)? Alternative solutions to my problem are welcomed.
// Case 1: Illegal because "where" can only have 1 base class
public void MyMethod<Ttype>(Ttype myClass) where Ttype : NetClassA, NetClassB {}
// Case 2: Legal to utlize multiple "where" interface types
public void MyMethod<Ttype>(Ttype myClass) where Ttype : INetClassA, INetClassB {}
// Case 3: For this to work ICommonNetMethods must be added to NetClassA/NetClassB
public void MyMethod<Ttype>(Ttype myClass) where Ttype : ICommonNetMethods {}
NetClassA() { This .NET class has method CommonMethod() }
NetClassB() { This .NET class has method CommonMethod() }
interface ICommonNetMethods { void CommonMethod() }
Thanks,
aidesigner
There are ways to solve this that involve creative thinking.
Most obvious:
Adapter Pattern
You build your interface, then two adapters where each take NetClassA and the other NetClassB. Your common code stays common and the specific lives in the adapters.
This works even for sealed classes. You do not dervice from NetClassA or NetClassB. I kind of want to leave this to you to figure out the implementation, come back in a day if you want the code implementation I'll post it.
Other things to look at:
Extension Methods
and/or
Reflection
More Help
=====================
= ICommonNetMethods =
=====================
| (derive)
|-------------------------------|
==================== ====================
= NetClassAAdapter = = NetClassBAdapter =
==================== ====================
| uses (not derive) | uses (not derive)
============= =============
= NetClassA = = NetClassB =
============= =============
Use Func<>:
Assume two classes, A and B, each with a function Foo (though this isn't really a requirement for this solution, observe class C, below):
public class A { int Foo() { return 1; } }
public class B { int Foo() { return 2; } }
public class C { int Deviant() { return 3; } }
Then in some code fragment, you will write:
var a = new A();
var b = new B();
var c = new C();
var fs = new Func<int>[] {() => a.Foo(), () => b.Foo(), () => c.Deviant()};
So to use this:
foreach(var func in fs)
Console.WriteLine(func());
Which in turn will output:
1
2
3
Lambda functions are a big deal in C#, and a great technology to learn. If you are unfamiliar, and would like to learn more, start at Microsoft's help page.
If you are looking at larger interfaces, consider, as has been mentioned, the adapter pattern. If the idea of wrapping each of your objects with their own concrete adapter classes seems like too much bloat for your buck, then again, Func<> to the rescue.
public interface ISomeInterface
{
void f1();
int f2(string p1);
...
}
public class FuncImplementation : ISomeInterface
{
public Action Func_f1 { get; set; }
public Func<string,int> Func_f2 { get; set; }
...
public void f1() { Func_f1(); }
public int f2(string p1) { return Func_f2(p1); }
...
}
Now you can make new Adapters inline:
var adaptA = new FuncImplementation { Func_f1 = MyF1, Func_f2 = Myf2 };
adaptA.f1();
You cannot impose an interface on existing code (unless you use a code weaver like PostSharp, but that's cheating ;-).
Instead, consider these options:
If you simply have a single method on your interface, you could use
a Delegate instead.
You could make a simple wrapper class for each of your types, and implement the interface there.
C# 4.0 introduced the dynamic keyword which allows C# developers to use duck typing (an alternative to the adapter pattern). With it, you could define MyMethod like this:
public void MyMethod(dynamic myClass)
{
myClass.CommonMethod();
}
You could then simply pass instances of NetClassA and NetClassB to MyMethod like this:
var a = new NetClassA();
var b = new NetClassB();
MyMethod(a);
MyMethod(b);
The drawback to this approach is that there's no static type checking. If NetClassA or NetClassB didn't have a method called CommonMethod that accepted no parameters, the program would compile, but fail at run time.
Also since there's no associated interface, it's not clear what functions and properties are available. Avoid using this approach in public facing assemblies.
The only way I can think of (off the top of my head) is to derive from the .NET class in question and add your interface to that implementation. I don't think that's the optimal solution, however.
Why not simply inspect the type that Ttype is in the method, and execute your code accordingly based on the type?
For example:
public void MyMethod<Ttype>(Ttype myClass)
{
string className = typeof(Ttype).Name;
switch (className)
{
case "NetClassA":
// Do stuff
break;
case "NetClassB":
// Do stuff
break;
default:
// Do something if necessary
break;
}
}
Thanks to all, I was really impressed with the various options. First I had already started pursing the delegate option ( The use of nested type parameters and recursion (C#) ) and have an almost ideal solution. The second post on this thread shows my exact implementation. This approach tries to solve the problem by passing just the needed function "Add" of NETClassA (SrgsItem) and NetClassB (SrgsElement) instead of the entire class. This is almost perfect except C# lack of "Generics Variance" support is getting in the way.
As to the other options they are all very insightful. After pursuing the delegate thread I will be trying the Adapter/Func approach proposed by Michael and Andrew (Will add comments). If you have time please follow the delegate thread above as it relates and it might help understand another facet of C#.
As of 2022, the best practice of C# is still to map external classes into Value Objects or Adaptors. To some people such as me, this is a logic overhead I wish to remove.
C# type system is closed in that we cannot extend an existing class with new interfaces. Of course, this can be mitigated by using a New-type Pattern.
class ExternalClass {
public string InfoWithDifferentLayoutOrName { get; }
}
interface IMyInterface {
string Info { get; }
}
record struct ExternalClassExtensionWrapper(ExternalClass Value): IMyInterface {
public string Info => Value.InfoWithDifferentLayoutOrName;
}
T MyAwesomeInnerFunc<T>(T input) where T: IMyInterface { ... }
But, from the view of code design, this approach does not cut down on code logic compared to a value-object mapper as you still have to write something like a wrapper. The only difference is whether you are depending on a concrete layout (VOs) or a contract (interfaces). A mysophobia do exist in the wild that insists interfaces bring lower coupling, but I don't see any lower cognitive burden in this specific case.
You will like a trait system where you can extend interfaces on others.
I've defined the following generic class
public class ManagedClass<T> where T : ManagedClass<T>
{
static ManagedClass()
{
Manager = new ObjectManager<T>();
}
public static ObjectManager<T> Manager { get; protected set; }
public ManagedClass()
{
Manager.Add( (T)this );
}
}
The idea is that I can use it like so:
class Product : ManagedClass<Product> {}
Now I can do something to the 7th product created like so:
Product.Manager.GetById(7).DoSomething();
The problem comes in if i try to use a derived class:
class ExtendedProduct : Product {}
now ExtendedProduct.Manager has a list of 'Products', and if i want to use a new function that I have added to ExtendedProduct (DoSomethingElse), I have to cast the object I get back like so:
((ExtendedProduct)ExtendedProduct.Manager.GetById(7)).DoSomethingElse();
This is a bit ugly, and the whole point of using generics for this is to avoid casting. I suppose I could add a static constructor to the derived class to set Manager = new ObjectManager() and add a new Manager.addObject( this ) in the derived class constructor, but It seems like there should be some better way of doing this using generics. Any suggestions?
The problem is that ExtendedProduct.Manager is the same thing as Product.Manager; the manager object can't act differently depending on where it's accessed from.
A couple of possibilities I can think of:
Hide the typecast inside the GetById method by making it generic:
Product.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();
Use one ObjectManager instance per subclass, connecting them privately if needed
Option 1 reminds me of NHibernate's ICriteria interface. It's effectively the same as a typecast, but a little harder to accidentally break.
Really what you're running into is a weakness with Generics. Once your class has resolved what type it's using for generics, you're somewhat restricted in what you can do.
Normally, I'd say Dependency Injection would be a savior here, but since the problematic method is static, that muddies up the waters.
I'd say the best thing is to have the ObjectManager class do the work for you:
static public class ObjectManager<T>
{
... the code that already exists in ObjectManager ...
static public U GetById<U>(long id)
{
object obj = GetById(id);
if (obj is U)
return (U)obj;
return default(U);
}
}
Then, in your code:
ExtendedProduct.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();
It's not really tons more elegant than casting, but may be one of the only solutions using Generics.