I'm trying to get an inheritance hierarchy of generics working, and I'm running into a bit of a problem.
Here's an example:
interface IFoo {}
interface IFoo<T> : IFoo
{
T Data { get; }
}
class Foo : IFoo<int> { public int Data { get; set; } }
interface IBar {}
class Bar : IBar { }
abstract class LayerOne<T_FOO, T_BAR> where T_FOO : IFoo where T_BAR : IBar {}
abstract class LayerTwo<T_FOO> : LayerOne<T_FOO, Bar> where T_FOO : IFoo, new()
{
protected T_FOO _foo = new T_FOO();
public void Test1() { _foo.Data.Dump();} // Compiler error
}
class LayerThree : LayerTwo<Foo>
{
public void Test2() { _foo.Data.Dump();}
}
I'm trying to get access to .Data in the LayerTwo class. Clearly, since IFoo doesn't have that property, it's going to error. However, if I change they type of T_FOO to IFoo<T>, then I have to define it and LayerThree as:
abstract class LayerTwo<T_FOO, T> : LayerOne<T_FOO, Bar> where T_FOO : IFoo<T>, new()
{
protected T_FOO _foo = new T_FOO();
public void Test1() { _foo.Data.Dump();}
}
class LayerThree : LayerTwo<Foo, int>
{
public void Test2() { _foo.Data.Dump();}
}
But the intent of the concrete Foo implementation is that it already knows it's implementing IFoo<int>. Is there any way I can get LayerTwo to know about the Data property without requiring it to be looked up from Foo and added to LayerThree's definition?
What I'd love is:
class LayerThree : LayerTwo<Foo> // Automatically realizes that the second generic is int
{
public void Test2() { _foo.Data.Dump();}
}
Update: As it turns out, I was actually trying to implement two contradictory things in my code. The actual LayerTwo was trying to keep T_FOO generic, but also created an (abstract) method which required a specific type from IFoo<T>.
So the solution I'm going with is just to use an interface which inherits from IFoo<T> and specifies the type, but I'm accepting Ondrej Tucny's answer, since it did solve the problem I asked about.
This is exactly the same situation as with IEnumerable / IEnumerable<T>. Your weakly typed interface IFoo needs to provide a weakly typed Data:
public interface IFoo
{
object Data { get; }
}
public interface IFoo<T> : IFoo
{
new T Data { get; }
}
then in the implementation one of the will be explicit to favor strongly typed access:
public class IntFoo : IFoo<int>
{
public int Data { get { return -1; } }
object IFoo.Data { get { return Data; } }
}
Now you have access to Data in either case, although when the actual type T is unknown, you have to live with an object.
Related
I have the following class relationships
public interface ICapability
{
}
public interface IBaseService<T> where T : ICapability
{
}
public abstract class BaseService<out T> : IBaseService<T> where T : ICapability
{
// modified...
T MapEventToCapability(dynamic eventData, T capability);
}
public class SomeCapability : ICapability
{
}
public partial class Service1 : BaseService<SomeCapability>
{
public Service1()
{
}
}
public class ServiceResolver
{
public void Register(BaseService<ICapability> serviceToRegister)
{
}
}
I try to invoke the Register method, passing in a new service1 as shown:
var b = new ServiceResolver();
var c = new Service1();
b.Register(c);
However I get a compile time error on c in the call to Register as follows;
Cannot convert Service1 to BaseService<ICapability>
I assumed that because Service1 is of type BaseService and that since SomeCapability is of type ICapability that this wouldn't be an issue.
I tried casting to BaseService as well I tried changing the input parameter on Register to be an IBaseService and again casting but then I get a runtime error.
Note the question has been updated since this answer was posted - covariance is no longer an option having added a method which is incompatible
You'll need to do 2 things to make this work
Make Register take IBaseService<ICapability> not BaseService<ICapability>
Make IBaseService covariant by marking the generic type as out - this is the same as the reason you can pass a List<Foo> to a merthod which expects an IEnumerable<Foo> as IEnumerable<T> is covariant in a similar manner.
public class ServiceResolver
{
public void Register(IBaseService<ICapability> serviceToRegister)
{
}
}
and
public interface IBaseService<out T>
where T : ICapability
{
}
Live example: https://dotnetfiddle.net/O0yXa5
I'm constantly running into the problem of having an abstract class that does all the heavy lifting and then I have a lot of polymorphic classes that customize the abstract to a specific need. The abstract generally needs a lot of parameters, so they all have to be passed from all polymorphic classes
public class FooComplex : AbstractFoo {
public FooComplex(IBarAwesome awesome, IBarCool cool, ...) : base(IBarAwesome awesome, IBarCool cool, ...) { }
...a lot of overriding abstracts
}
public class FooSimple : AbstractFoo
{
public FooSimple(IBarAwesome awesome, IBarCool cool, ...) : base(IBarAwesome awesome, IBarCool cool, ...) { }
...little bit of overriding abstracts
}
public class AbstractFoo
{
public AbstractFoo(IBarAwesome awesome, IBarCool cool, ...)
...heavy lifting
}
Is there anything I can do to not pass all these things, but be able to unit test them? I've always been taught that doing
var awesome = container.Resolve<IBarAwesome>();
In like say the constructor is bad practice.
The reason I would like to find a solution to this, is it makes it harder and hard to pass anything new into the abstract class as I have to copy and pass the same parameters into many polymorphic subclasses.
I believe this is similar to what #C.Evenhuis mentioned in the comments by abstracting your constructor parameters into a common interface so they can be passed as single constructor parameter as well as being easily tested.
Concrete Classes:
public class FooComplex : AbstractFoo
{
public FooComplex(ComplexParam complexParam) : base(complexParam)
{}
}
public class FooSimple : AbstractFoo
{
public FooSimple(SimpleParam simpleParam) : base(simpleParam)
{}
}
Single Generic Concrete Class (Optional)
With this class, you could pass any type into the constructor which inherits IParams and potentially remove the need for FooComplex and FooSimple.
public class Foo<T> : AbstractFoo where T : IParam
{
public Foo(T param) : base(param)
{ }
}
Base Abstract Class:
public abstract class AbstractFoo
{
protected AbstractFoo(IParam parameter) { }
}
Interfaces:
public interface IBarCool : IBar
{}
public interface IBarAwesome : IBar
{}
public interface IBar
{}
public interface IParam
{
IEnumerable<IBar> Param { get; }
}
Reusable Concrete Parameters:
I personally don't like this method below because of the repetition but I suppose if each of the classes have their own separate implementation then it's okay. Another option would be to just have a class called ParameterHolder and two instances of the class named appropriately e.g. var complex = new ParameterHolder() and pass to the Generic Foo<T>.
public class ComplexParam : IParam
{
public IEnumerable<IBar> Param { get; }
public ComplexParam(IEnumerable<IBar> complexParam)
{
Param = complexParam;
}
}
public class SimpleParam : IParam
{
public IEnumerable<IBar> Param { get; }
public SimpleParam(IEnumerable<IBar> simpleParam)
{
Param = simpleParam;
}
}
All that needs to happen is:
public interface IAbstractParams
{
IBarAwesome awesome { get; }
IBarCool cool { get; }
...
}
public class FooComplex : AbstractFoo
{
public FooComplex(IAbstractParams params) : base(params) { }
...a lot of overriding abstracts
}
public class FooSimple : AbstractFoo
{
public FooSimple(IAbstractParams params) : base(params) { }
...little bit of overriding abstracts
}
public class AbstractFoo
{
protected readonly IBarAwesome _awesome;
protected readonly IBarCool _cool;
public AbstractFoo(IAbstractParams params)
{
_awesome = params.awesome;
_cool = params.cool;
}
...heavy lifting
}
then you need to add the nuget package Autofac.Extras.AggregateService and add this line to your builder:
builder.RegisterAggregateService<IAbstractParams>();
Thank you to #Travis Illig and #C.Evenhuis for helping me come up with this solution.
For more complex solutions to this same problem please look at #Kitson88
lately I started to learn generics. I run into trouble with storing references to generic classes instances. As you can see, my class ListHandler can store references to specific type of BaseClass. I would love to register BaseClass instances by themselves, which is why I wanted to guarantee that they will use BaseParamClass by adding 'where'. Anyway - it does not compile.'This', does not know that T is actually BaseClassParam even with 'where' keyword in class. I don't know what is wrong here and I couldn't find answer anywhere. I would be grateful for tips/guides/solutions.
public class ListHandler
{
private List<BaseClass<BaseParamClass>> list;
public ListHandler()
{
list = new List<BaseClass<BaseParamClass>>();
}
public void Register(BaseClass<BaseParamClass> param)
{
list.Add(param);
}
}
public class BaseClass<T> where T : BaseParamClass
{
private ListHandler listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this); //throws error
}
}
Why don't you make ListHandler generic as well?
public class ListHandler<T>
{
private List<BaseClass<T>> list;
public ListHandler()
{
list = new List<BaseClass<T>>();
}
public void Register(BaseClass<T> param)
{
list.Add(param);
}
}
public class BaseClass<T>
{
private ListHandler<T> listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler<T> listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
}
Also, it seems strange to me to have BaseClass<T> contain a reference to a class that has a reference to BaseClass<T> itself.
I have another option for you.
Let's split the BaseClass<T> class into two with a non-generic base, like so:
public class BaseClass
{
protected ListHandler listHandler;
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
}
}
public class BaseClass<T> : BaseClass where T : BaseParamClass
{
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
: base(listHandler)
{
listHandler.Register(this); // Compiles nicely! Yay!
}
}
Now, the list inside ListHandler can be defined as private List<BaseClass> list;. That means there is no problem adding any BaseClass item to the list. We also can then define two methods for registering and fetching generic versions of the BaseClass<T> from the ListHandler. It would look like this:
public class ListHandler
{
private List<BaseClass> list;
public ListHandler()
{
list = new List<BaseClass>();
}
public void Register<T>(BaseClass<T> param) where T : BaseParamClass
{
list.Add(param);
}
public BaseClass<T> Fetch<T>() where T : BaseParamClass
{
return list.Select(x => x as BaseClass<T>).Where(x => x != null).FirstOrDefault();
}
}
So, given a class public class FooParam : BaseParamClass { } I can write this code:
ListHandler listHandler = new ListHandler();
BaseClass<FooParam> baseClass = new BaseClass<FooParam>(listHandler);
BaseClass<FooParam> baseClass2 = listHandler.Fetch<FooParam>();
Console.WriteLine(object.ReferenceEquals(baseClass, baseClass2));
The result from this code is True is written to the console - which means I can successfully fetch the instance of BaseClass<FooParam> from the ListHandler.
Why your code doesn't compile
In order to fully understand why your code doesn't compile, you'll have to dive into covariance and contravariance, which is a big topic and hard to explain in an SO answer. It can be especially confusing if you've gotten to a point where inheritance polymorphism is second nature to you; the rules are just different enough to be make your head hurt.
Here is what is confusing--
You're used to doing this:
object a = new String(...);
But generics don't let you do this!
List<object> c = new List<string>(); //Compiler error
That's because those two Lists are not related the same way that object and string are related. One does not inherit from the other. Rather, they are different variants of a generic type definition. In the generic world, you can't assign one to the other. The same is true of this:
void Foo<T>() where T: BaseParamClass
{
BaseClass<BaseParamClass> a = new BaseClass<T>(); //Compiler error
}
In this example, T could be BaseParamClass or one of its derived types. They are not the same type. So to remain type-safe, the compiler has to disallow this assignment, and your Register call, which has the same type mismatch.
Standard ways around this
You need a covariant interface. These allow assignment from derived to base. So for example, while this is still illegal:
List<object> a = new List<string>(); //Compiler error
This is totally fine:
IEnumerable<object> e = new List<string>(); //Is OK
Because IEnumerable was declared to be covariant, like this:
interface IEnumerable<out T>
Which means it is can be assigned in this way. It works because using out also adds a compiler constraint to the interface: it can be used to retrieve stuff...
interface IEnumerable<out T>
{
T Item[int index];
}
...but it cannot accept anything:
interface IEnumerable<out T>
{
Add(T item); //Compiler error
}
These constraints are what allow generics to provide early-bound type safety while still allowing certain forms of (non-inheritance) polymorphism.
What I'd suggest
Based on your comment, it sounds like you just need a container (a stack, apparently) that can hold references to these BaseClass<T> instances. If you are following separation of concerns, the stack doesn't need to actually do anything with the T, other than store it and retrieve it, and to allow it to register itself.
Since that is a separate concern, make a separate interface.
And in the interest of keeping things simple, maybe avoid using generics completely for this bit.
One way to do it--
Create an interface that allows access to everything the stack needs to know about an item it is containing. For example, if the stack contains popups of various kinds, you may want to expose the popup's title.
interface IStackable
{
string Title { get; set; }
}
Now use it like this:
public class ListHandler
{
private readonly Dictionary<string, IStackable> list;
public ListHandler()
{
list = new Dictionary<string, IStackable>();
}
public void Register(IStackable item)
{
list.Add(item.Title, item);
}
}
public class BaseClass<T> : IStackable where T : BaseParamClass
{
private ListHandler listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
public string Title { get; set; }
}
Unless there is some other requirement, you shouldn't need to make it any more complicated than that.
All you really need to do is add an interface. This works:
public class BaseParamClass
{
}
public class ListHandler
{
private List<IBase<BaseParamClass>> list;
public ListHandler()
{
list = new List<IBase<BaseParamClass>>();
}
public void Register(IBase<BaseParamClass> param)
{
list.Add(param);
}
}
public interface IBase<T> where T : BaseParamClass
{
T Param {get; }
}
public class BaseClass : IBase<BaseParamClass>
{
private ListHandler listHandler;
public BaseParamClass Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
}
Working code on DotNetFiddle
I have completely re-written this hoping to make my question clearer. I have chosen the concept of services making use of repositories in my example code.
Example code:
class Program
{
interface IEntity
{
int Id { get; set; }
}
// Example entity could be:
class Book : IEntity
{
public int Id { get; set; }
}
class Magazine : IEntity
{
public int Id { get; set; }
}
interface IRepository<TEntity> where TEntity : class, IEntity
{
IEnumerable<TEntity> GetEntities();
}
interface IBooksRepository : IRepository<Book> { }
interface IMagazineRepository : IRepository<Magazine> { }
class DataStore<TEntity> where TEntity: class, IEntity
{
public IEnumerable<TEntity> GetFromStore()
{
throw new NotImplementedException();
}
}
abstract class RepositoryBase<TEntity> : IRepository<TEntity>
where TEntity : class, IEntity
{
DataStore<TEntity> _dataStore;
public RepositoryBase()
{
_dataStore = new DataStore<TEntity>();
}
public IEnumerable<TEntity> GetEntities()
{
return _dataStore.GetFromStore();
}
}
class BookRepository : RepositoryBase<Book>, IBooksRepository { }
class MagazineRepository : RepositoryBase<Magazine>, IMagazineRepository { }
abstract class ServiceBase<IEntityRepository, TEntity>
where IEntityRepository : IRepository<TEntity>
where TEntity : class, IEntity
{
IEntityRepository _repository;
public ServiceBase(IEntityRepository repository)
{
_repository = repository;
}
public IEnumerable<TEntity> GetEntitiesFromRepository()
{
return new List<TEntity>();
}
}
class BookService : ServiceBase<IBooksRepository, Book>
{
public BookService(IBooksRepository bookRepository)
: base(bookRepository)
{ }
}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>
{
public MagazineService(IMagazineRepository magazineRepository)
: base(magazineRepository)
{ }
}
static void Main(string[] args)
{
var aBookService = new BookService(new BookRepository());
var aMagazineService = new MagazineService(new MagazineRepository());
var books = aBookService.GetEntitiesFromRepository();
var magazines = aMagazineService.GetEntitiesFromRepository();
}
}
This all works fine and perhaps it is valid to ask why I want to change this. Mainly I am just curious if I can make this more neat. It is more a point of curiosity that one of functional correctness I suppose.
Both IBookRepository and IMagazineRepository know which concreate type they represent 'Book' and 'Magazine'
When I define my concreate services: BookService and MagazineService I have to specify the type as well as the interface:
class BookService : ServiceBase<IBooksRepository, Book>{}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>{}
I wondered if I could simplify thier signatures as the Interfaces already know The type I am expecting Book or Magazine.
Can I extract the Entity Type from the inteface such that I no longer need to specify the type when creating concreate service types?
As I pondered this, I discovered a deeper issue with my knowledge of C#:
What exactly is the type of 'thing' that the generic system is looking for between those angle brackets: IEnumerable<TThisThing>.
When I look at intellisense is says T is the type of objects to enumerate.
So as an experiment I grabbed the type of MyType:
Type typeOfMyType = instanceOfMyType.GetType();
IEnumerable<typeOfMyType> enumerable = new List<typeOfMyType>(); //crude example.
Now of course this does not work. So what kind of thing is TThisThing that works between the angle brackets?
is there a way of extracting this information so that I can forgo the
inclusion of 'MyType' in the class definition and use the discovered
TMyType in the example method?
Yes, you simply need to define the generic type parameter in the methods name:
public IEnumerable<TMyType> GetMyTypes<TMyType>()
{
// get list of TMyType instances;
return list;
}
If you don't want to use a generic type parameter at all, you'll have to defer to reflection, and you won't be able to use a compile-time generic type such as returning an IEnumerable<T>.
So what kind of thing is TThisThing that works between the angle
brackets?
TThisThing should be a compile-time known type parameter. When you use Type typeOfMyType = instanceOfMyType.GetType();, the type of instanceOfMyType is only known at run-time.
For example:
var obj = new SomeClass<Foo>();
IEnumerable<Bar> bars = obj.GetMyTypes<Bar>();
Where Foo and Bar:
public class Foo { }
public class Bar { }
I have a base class that takes a single generic argument. I then have several classes that inherit from this base class. Is there a simple way for the child classes to inherent a factory from the base class?
Example
class BaseClass<T>
{
T Value {get; set;}
string Name {get; set;}
public static BaseClass<T> Factory(T Value)
{
return new BaseClass<T>(Value);
}
}
class ChildClass : BaseClass<int>
{
public void Test()
{
// I want this below to work
// but Factory() returns a BaseClass
ChildClass bs = ChildClass.Factory(10);
}
}
I've noted in the code what I want to work. I can think of one way to overcome this, by adding an implicit operator to either BaseClass or SubClass that converts from BaseClass to ChildClass.
I can also just explicitly add the Factory to ChildClass but that defeats the point of inheritance.
Is there a better, more standardized way of doing this?
I would do something like this:
class BaseClass<T, K> where K : BaseClass<T, K>, new()
{
T Value { get; set; }
string Name { get; set; }
public static K Factory(T value)
{
return new K { Value = value };
}
}
class ChildClass : BaseClass<int, ChildClass>
{
public void Test()
{
ChildClass cs = Factory(10);
}
}
It's a bit hard to answer your question since you have described what you are trying to do, but not why. Hence I got to try to guess what you want.
I would not put the factory method in the same class as in the other answer or your question. How would you handle inheritance for once? It works for the two levels that you have. But what if you want to extend ChildClass?
Instead I would create a generic factory used for the object creation. Implement it has a singleton wrapped around a factory interface to be able to easy extend it or swap the implementation.
class MyFactory
{
private static IMyFactory _instance;
public static void Assign(IMyFactory factory) { _instance = factory; }
public static T Create<T>() { return _instance.Create<T>(); }
}
interface IMyFactory
{
T Create<T>();
}
class MyFactoryImp : IMyFactory
{
//do whatever needed in here
public T Create<T>(){ return new T(); }
}
class BaseClass<T>
{
T Value {get; set;}
string Name {get; set;}
}
class ChildClass : BaseClass<int>
{
public void Test()
{
ChildClass bs = MyFactory.Create<ChildClass>(10);
}
}
// start with this, you can easily switch implementation
MyFactory.Assign(new MyFactoryImp());
The other obvious answer would be to start using a Inversion Of Control container, for example autofac.