I know I'm not doing this right, but I also know there is a way to do this. I'm trying to be as generic and abstract as possible, otherwise my code is going to get real messy. So I'm using strategy pattern here as well, which is the GetAggregateClient() method.
I want to have an abstract class called AbstractAggregate<T>, so that it uses generics. The generic type will be a series of data classes (BlogItem, ResourceItem, and AskItem), which all inherit from ListItem.
So that's the background info.
The problem here is that I want GetAbstractAggregate() to return an instance of one of the client classes that implements AbstractAggregate, with the type of item specified depending on the enum passed in. However, I cannot return an AbstractAggregate<T>. The compiler won't let me, and that makes sense since, since the AbstractAggregateFactory class is not a generic.
Does anyone know the best way to do this?
Thanks a lot.
public static class AggregateHelper
{
public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources }
}
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient(AggregateHelper.AggregateTypes type)
{
switch (type)
{
case AggregateHelper.AggregateTypes.AskTankTruck:
return new AskTankTruckAggregate<AskItem>();
case AggregateHelper.AggregateTypes.TankTruckBlog:
return new TankTruckBlogAggregate<BlogItem>();
case AggregateHelper.AggregateTypes.Resources:
return new ResourcesAggregate<ResourceItem>();
default:
throw new AggregateDoesNotExistException();
}
}
}
public abstract class AbstractAggregate<T>
{
public abstract List<T> GetAggregate(Guid[] resourcetypes);
public abstract T GetSingle(string friendlyname);
}
public class AskTankTruckAggregate<T> : AbstractAggregate<T>
{
// not implemented yet
}
public class TankTruckBlogAggregate<T> : AbstractAggregate<T>
{
// not implemented yet
}
public class ResourcesAggregate<T> : AbstractAggregate<T>
{
// not implemented yet
}
The problem the compiler complains about is that you have a method which is 'open' (T) - and you're returning closed generic (with <AskItem> etc.), concrete type really.
i.e. you have to return a <T> - and you can do that with the method - no matter if the factory is not generic, the method still can be.
As for what's the best way to do it, that's more of a design question, and a bit longer story. I'm not entirely sure what you're trying to achieve (maybe some background story, how many types you might have etc.)
First, your items shouldn't (generally speaking, as a best practice or some 'feels good' factor) inherit from ListItem. Use some other base class of yours, and if you need a collection, use a generic one like List<T>, or create your own IList implementation, etc.
Second, you don't need to make everything generic. Your base aggregator is generic but custom classes are not, usually. For example:
abstract class ItemBase { }
class AskItem : ItemBase { }
class BlogItem : ItemBase { }
class ProvderA : ProviderBase<AskItem>
{
public override AskItem Get()
{
throw new NotImplementedException();
}
}
class ProvderB : ProviderBase<BlogItem>
{
public override BlogItem Get()
{
throw new NotImplementedException();
}
}
abstract class ProviderBase<T> where T : ItemBase
{
public abstract T Get();
}
class Program
{
static void Main(string[] args)
{
ProviderBase<AskItem> provider = GetProvider<AskItem>();
var item = provider.Get();
}
static ProviderBase<T> GetProvider<T>() where T : ItemBase
{
if (typeof(T) == typeof(AskItem))
return (ProviderBase<T>)(object)new ProvderA();
if (typeof(T) == typeof(BlogItem))
return (ProviderBase<T>)(object)new ProvderB();
return null;
}
}
...that's one implementation.
Basically, making everything 'generic' is not always the best way. You have to have enough reasons or 'types' unknown to be possibly used. As with generic you also pay a certain price. Crossing generics to non-generics world is often tricky, and involves reflection if your types can't be inferred by the usage etc.
In my opinion, it's a mistake making each provider generic (<T>), as it only accepts one type (each concrete), while base is generic. So like the above. Usually generic is also constrained per interface where/where you can.
But then you have a problem, as casting back to generic context from effectively a non-generic class is not straight (also have in mind there are caveats with value types as you often have to treat that differently), and vice versa as well.
Hence you need something like cast (object) first.
I'd rather use sort of an IOC approach here - e.g. look at the autofac (I'm not associated but I like how it works, nice framework). In that case you'd do something like this:
container.Register<ProviderBase<AskItem>>(c=> new ProvderA());
container.Register<ProviderBase<BlogItem>>(c => new ProvderB());
// and query later...
ProviderBase<AskItem> provider = container.Resolve<ProviderBase<AskItem>>();
Hope this helps some.
I'm not sure I understand what you are trying to achieve but perhaps it's something like this
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>()
{
if(T is AskItem) return new AskTankTruckAggregate();
if(T is BlogItem) return new TankTruckBlogAggregate();
if(T is ResourceItem) return new ResourcesAggregate();
}
}
public abstract class AbstractAggregate<T>
{
public abstract List<T> GetAggregate(Guid[] resourcetypes);
public abstract T GetSingle(string friendlyname);
}
public class AskTankTruckAggregate : AbstractAggregate<AskItem>
{
//not implemented yet
}
public class TankTruckBlogAggregate : AbstractAggregate<BlogItem>
{
//not implemented yet
}
public class ResourcesAggregate : AbstractAggregate<ResourceItem>
{
//not implemented yet
}
I'm trying to be as generic and abstract as possible, otherwise my code is going to get real messy.
this is a misconception. being generic/abstract can actually complicate an otherwise simple problem. The key to clean code is encapsulation. much different that inheritance or generics.
In this case I think composition would be a better choice, rather than inheritance. with a set of adaptors you could have a common object that each entity could be adpated to. for example:
interface ICommon { ... }
class AskAdaptor: ICommon
{
private readonly Ask ask;
publick AskAdaptor(Ask ask)
{
this.ask = ask;
}
}
class AskAdaptor: ICommon
{
private readonly Blog blog;
publick AskAdaptor(Blog blog)
{
this.blog = blog;
}
}
class AskAdaptor: ICommon
{
private readonly Resource resource;
publick AskAdaptor(Resource resource)
{
this.resource = resource;
}
}
class CommonAggregate
{
public void Add(ICommon common)
{
....
}
}
How about this:
public static class AggregateHelper
{
public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources }
}
public class AskItem { }
public class BlogItem { }
public class ResourceItem { }
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>
(AggregateHelper.AggregateTypes type)
{
switch (type)
{
case AggregateHelper.AggregateTypes.AskTankTruck:
return new AskTankTruckAggregate<T>();
case AggregateHelper.AggregateTypes.TankTruckBlog:
return new TankTruckBlogAggregate<T>();
case AggregateHelper.AggregateTypes.Resources:
return new ResourcesAggregate<T>();
default:
throw new ArgumentException();
}
}
}
public abstract class AbstractAggregate<T>
{
public abstract List<T> GetAggregate(Guid[] resourcetypes);
public abstract T GetSingle(string friendlyname);
}
public class AskTankTruckAggregate<T> : AbstractAggregate<T>
{
public override List<T> GetAggregate(Guid[] resourcetypes)
{
throw new NotImplementedException();
}
public override T GetSingle(string friendlyname)
{
Console.WriteLine(friendlyname);
Type whats_t = typeof(T);
return default(T);
}
}
public class TankTruckBlogAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
public class ResourcesAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
Example:
AbstractAggregate<BlogItem> foo3 =
AbstractAggregateFactory.GetAggregateClient<BlogItem>(AggregateHelper.AggregateTypes.AskTankTruck);
foo3.GetSingle("test");
One thing that is possibly clear is that your design is somewhat flawed. A switch on type is not the best thing to do in a generic method which defeats it's purpose. But what is not clear is what the purpose of your classes are.
Some speculations:
1) Seeing your pair classes AskItem and AskTankTruckAggregate<T> etc I dont think the latter has to be a generic class, it is a very specific class, tightly coupled to AskItem. I would redesign it like
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem
{
//use reflection to find the type that inherits AbstractAggregate<T>
//instantiate the type
//cast to AbstractAggregate<T> and return
}
}
public class AskTankTruckAggregate : AbstractAggregate<AskItem>
{
//not implemented yet
}
public class TankTruckBlogAggregate : AbstractAggregate<BlogItem>
{
//not implemented yet
}
public class ResourcesAggregate : AbstractAggregate<ResourceItem>
{
//not implemented yet
}
Call it like:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
2) Another way: delegate the aggregate creation job to your ListItems.
public abstract class ListItem //or interface
{
protected abstract object Create();
}
public class AskItem : ListItem { //implement to return AskTankTruckAggregate
}
public class BlogItem : ListItem { //implement to return TankTruckBlogAggregate
}
public class ResourceItem : ListItem { //implement to return ResourcesAggregate
}
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem, new()
{
return (AbstractAggregate<T>)new T().Create();
}
}
public class AskTankTruckAggregate : AbstractAggregate<AskItem>
{
//not implemented yet
}
public class TankTruckBlogAggregate : AbstractAggregate<BlogItem>
{
//not implemented yet
}
public class ResourcesAggregate : AbstractAggregate<ResourceItem>
{
//not implemented yet
}
Call it like:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
3) Or the same, but make it a bit more strongly typed, with the use of generics:
public abstract class ListItem<T> where T : ListItem<T> //or interface
{
protected abstract AbstractAggregate<T> Create();
}
public class AskItem : ListItem<AskItem> { //implement to return AskTankTruckAggregate
}
public class BlogItem : ListItem<BlogItem> { //implement to return TankTruckBlogAggregate
}
public class ResourceItem : ListItem<ResourceItem> { //implement to return ResourcesAggregate
}
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem, new()
{
return new T().Create();
}
}
public class AskTankTruckAggregate : AbstractAggregate<AskItem>
{
//not implemented yet
}
public class TankTruckBlogAggregate : AbstractAggregate<BlogItem>
{
//not implemented yet
}
public class ResourcesAggregate : AbstractAggregate<ResourceItem>
{
//not implemented yet
}
Call it like:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
4) Lastly, may be make the return type less generic? Involves switch case, I dont like it.
public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources }
public static class AbstractAggregateFactory
{
public static AbstractAggregate GetAggregateClient(AggregateTypes type)
{
switch (type)
{
case AggregateTypes.AskTankTruck:
return new AskTankTruckAggregate<AskItem>();
case AggregateTypes.TankTruckBlog:
return new TankTruckBlogAggregate<BlogItem>();
case AggregateTypes.Resources:
return new ResourcesAggregate<ResourceItem>();
default:
throw new AggregateDoesNotExistException();
}
}
}
public abstract class AbstractAggregate
{
}
public abstract class AbstractAggregate<T> : AbstractAggregate
{
}
//or change the definition to AskTankTruckAggregate : AbstractAggregate<AskItem>
public class AskTankTruckAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
//or change the definition to TankTruckBlogAggregate : AbstractAggregate<BlogItem>
public class TankTruckBlogAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
//or change the definition to ResourcesAggregate : AbstractAggregate<ResourceItem>
public class ResourcesAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
Call it like:
AbstractAggregateFactory.GetAggregateClient(AggregateTypes.AskTankTruck); //etc
Imo, this approach is worse than the reflection approach. Its easy to forget some enum checking in future.
Of all, 3rd looks the best to my eyes, but again without knowing your design goal, its very difficult to predict. Few suggestions:
Your factory name sounds better like AggregateFactory. "Abstract" in it makes it more about implementation.
In case you need an enum to denote type, do not make it nested. Nested public types are harder to call. Take out the wrapping static class (as in my 5th approach).
Rename your base class as Aggregate<T> or AggregateBase<T>. Again "Abstract" in it makes it more about implementation, quite needless.
Related
This is probably a classic covariance/contravariance question, it looks like it should work but I'm probably missing a trick.
I'm attempting to return a less derived type from a factory method, but I find that I cannot cast the more specialized concrete instance to a less derived base type.
public class AnimalSettings { ... }
public class CatSettings : AnimalSettings { ... }
public interface IAnimalService<TSettings> { ... }
public abstract AnimalService<TSettings> : IAnimalService<TSettings> where TSettings : AnimalSettings { ... }
public class CatService : AnimalService<CatSettings> { ... }
Then, in a factory method I have:
public static IAnimalService<AnimalSettings> GetAnimalService(AnimalType selector)
{
switch (selector)
{
case AnimalType.Cat:
return (IAnimalService<AnimalSettings>) new CatService();
break;
}
}
and the intention is to be able to do the following:
var service = MyServiceFactory.GetAnimalService(AnimalType.Cat);
service.DoAnimalBehavior();
This compiles fine, but at runtime my code is failing in the attempted cast return (IAnimalService<AnimalSettings>) new CatService();, with an InvalidCastException.
How should I be casting my more derived type to a less derived type so that callers can use that interfaced base type to invoke functionality?
Changing the cast to (IAnimalservice<CatSettings>) new CatService() does work, but it's intended that the caller receives a IAnimalservice<AnimalSettings> so that it can handle any sort of animal (In other words, the caller should not be using any of the more specialized types). Should I be specifying an in or out as part of the generic definition somewhere?
By giving a complete example it would be much easier to help. ;-)
So here is the working code. And as Sweeper already mentioned, you need to add the out parameter at the interface to make it work.
using System;
public class Program
{
public static void Main()
{
var catService = new CatService(new CatSettings());
var genericService = (IAnimalService<AnimalSettings>)catService;
genericService.DoAnimalBehavior();
}
}
public abstract class AnimalSettings
{
public abstract void DoAnimalBehavior();
}
public class CatSettings : AnimalSettings
{
public override void DoAnimalBehavior()
{
Console.WriteLine("Meeoh");
}
}
public interface IAnimalService<out TSettings>
{
void DoAnimalBehavior();
}
public abstract class AnimalService<TSettings> : IAnimalService<TSettings> where TSettings : AnimalSettings
{
private readonly TSettings _settings;
public AnimalService(TSettings settings)
{
_settings = settings;
}
public void DoAnimalBehavior()
{
_settings.DoAnimalBehavior();
}
}
public class CatService : AnimalService<CatSettings>
{
private readonly CatSettings _catSettings;
public CatService(CatSettings catSettings)
: base(catSettings)
{
_catSettings = catSettings;
}
}
I have the following classes
public abstract class BaseViewPresenter { }
public abstract class BaseView<T> : UserControl
where T : BaseViewPresenter { }
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> { }
I have a method that looks like this (simplified)
public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
// Correctly creates BaseView object
var control = Activator.CreateInstance(viewType);
// Fails to cast as BaseView<BaseViewPresenter> so returns null
return control as BaseView<BaseViewPresenter>;
}
When I call this using an instances of LoginPresenter
var login = new LoginPresenter();
var ctl = Resolve(login);
The line Activator.CreateInstance(viewType) correctly resolves into a new instances of my LoginView, however control as BaseView<BaseViewPresenter> can't do the cast correctly so returns null.
Is there a way to correctly cast the control into BaseView<BaseViewPresenter> without using specific type generics?
Since LoginView inherits from BaseView<LoginPresenter>, and LoginPresenter inherits from BaseViewPresenter, I would assume there's a way to convert LoginView to BaseView<BaseViewPresenter>.
I am stuck with using .Net 3.5
This is a very frequently asked question. Let's rename your types:
abstract class Fruit { } // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // was LoginView
Your question now is:
I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.
No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.
Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:
The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.
Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
I accepted Eric's answer since it provides a great explanation of why what I wanted wasn't possible, but I also thought I'd share my solution in case anyone else runs into this same problem.
I removed the generic type parameter from my original BaseView class, and created a 2nd version of the BaseView class that included the generic type parameter and specifics for it.
The first version is used by my .Resolve() method or other code that doesn't care about the specific types, and the second version is used by any code that does care, such as the implentation of a BaseView
Here's an example of how my code ended up looking
// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl
{
public BaseViewPresenter Presenter { get; set; }
}
public abstract class BaseView<T> : BaseView
where T : BaseViewPresenter
{
public new T Presenter
{
get { return base.Presenter as T; }
set { base.Presenter = value; }
}
}
// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter>
{
// Can now call things like Presenter.LoginPresenterMethod()
}
// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
BaseView view = Activator.CreateInstance(viewType) as BaseView;
view.Presenter = presenter;
return view;
}
You're expecting to treat the type as being covariant with respect to the generic argument. Classes can never be covariant; you'd need to use an interface rather than (or in addition to) an abstract class to make it covariant with respect to T. You'd also need to be using C# 4.0.
My usual solution to this problem is to create an intermediary class that has access to the type-parametric class's methods through delegates. Fields can also be accessed through getters/setters.
The general pattern goes:
public abstract class Super {}
public abstract class MyAbstractType<T> where T : Super {
public MyGeneralType AsGeneralType() {
return MyGeneralType.Create(this);
}
// Depending on the context, an implicit cast operator might make things
// look nicer, though it might be too subtle to some tastes.
public static implicit operator MyGeneralType(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
public int field;
public void MyMethod1() {}
public void MyMethod2(int argument) {}
public abstract bool MyMethod3(string argument);
}
public delegate T Getter<T>();
public delegate void Setter<T>(T value);
public delegate void MyMethod1Del();
public delegate void MyMethod2Del(int argument);
public delegate bool MyMethod3Del(string argument);
public class MyGeneralType {
public Getter<int> FieldGetter;
public Setter<int> FieldSetter;
public MyMethod1Del MyMethod1;
public MyMethod2Del MyMethod2;
public MyMethod3Del MyMethod3;
public static MyGeneralType Create<T>(MyAbstractType<T> t) where T : Super {
var g = new MyGeneralType();
g.FieldGetter = delegate { return t.field; };
g.FieldSetter = value => { t.field = value; };
g.MyMethod1 = t.MyMethod1;
g.MyMethod2 = t.MyMethod2;
g.MyMethod3 = t.MyMethod3;
return g;
}
public int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
The above exemplifies getting all the methods and fields but normally I only need a few of them. This is a general solution to the problem and one could feasibly write a tool to generate these intermediary classes automatically, which I might at some point.
Try it here: https://dotnetfiddle.net/tLkmgR
Note that this is enough for all my cases, but you can be extra hacky with this:
public abstract class MyAbstractType<T> where T : Super {
// ... Same everything else ...
// data fields must become abstract getters/setters, unfortunate
public abstract int field {
get;
set;
}
public static implicit operator MyAbstractType<Super>(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
}
public class MyGeneralType : MyAbstractType<Super> {
// ... same constructors and setter/getter
// fields but only keep method fields
// that contain the method references for
// implementations of abstract classes,
// and rename them not to clash with the
// actual method names ...
public MyMethod3Del myMethod3Ref;
// Implement abstract methods by calling the corresponding
// method references.
public override bool MyMethod3(string argument) {
return myMethod3Ref(argument);
}
// Same getters/setters but with override keyword
public override int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
And there you go, now you can literally cast a MyAbstractType<Sub> where Sub : Super to a MyAbstractType<Super>, although it's no longer the same object anymore, but it does retain the same methods and data, it's sort of a complex pointer.
public class Sub : Super {}
public class MySubType : MyAbstractType<Sub> {
public int _field;
public override int field {
get { return _field; }
set { _field = value; }
}
public override bool MyMethod3(string argument) {
Console.WriteLine("hello " + argument);
return argument == "world";
}
}
public class MainClass {
public static void Main() {
MyAbstractType<Sub> sub = new MyAbstractType<Sub>();
MyAbstractType<Super> super = sub;
super.MyMethod3("hello"); // calls sub.MyMethod3();
super.field = 10; // sets sub.field
}
}
This isn't as good in my opinion, the other version of MyGeneralType is a more straighforward layer over the concrete types, plus it doesn't require rewriting the data fields, but it does actually answer the question, technically. Try it here: https://dotnetfiddle.net/S3r3ke
Example
Using these abstract classes:
public abstract class Animal {
public string name;
public Animal(string name) {
this.name = name;
}
public abstract string Sound();
}
public abstract class AnimalHouse<T> where T : Animal {
List<T> animals;
public AnimalHouse(T[] animals) {
this.animals = animals.ToList();
}
public static implicit operator GeneralAnimalHouse(AnimalHouse<T> house) {
return GeneralAnimalHouse.Create(house);
}
public List<string> HouseSounds() {
return animals.Select(animal => animal.Sound()).ToList();
}
}
We make this "general" variant:
public delegate List<string> HouseSoundsDel();
public class GeneralAnimalHouse {
public HouseSoundsDel HouseSounds;
public static GeneralAnimalHouse Create<T>(AnimalHouse<T> house) where T : Animal {
var general = new GeneralAnimalHouse();
general.HouseSounds = house.HouseSounds;
return general;
}
}
And finally with these inheritors:
public class Dog : Animal {
public Dog(string name) : base(name) {}
public override string Sound() {
return name + ": woof";
}
}
public class Cat : Animal {
public Cat(string name) : base(name) {}
public override string Sound() {
return name + ": meow";
}
}
public class DogHouse : AnimalHouse<Dog> {
public DogHouse(params Dog[] dogs) : base(dogs) {}
}
public class CatHouse : AnimalHouse<Cat> {
public CatHouse(params Cat[] cats) : base(cats) {}
}
We use it like this:
public class AnimalCity {
List<GeneralAnimalHouse> houses;
public AnimalCity(params GeneralAnimalHouse[] houses) {
this.houses = houses.ToList();
}
public List<string> CitySounds() {
var random = new Random();
return houses.SelectMany(house => house.HouseSounds())
.OrderBy(x => random.Next())
.ToList();
}
}
public class MainClass {
public static void Main() {
var fluffy = new Cat("Fluffy");
var miu = new Cat("Miu");
var snuffles = new Cat("Snuffles");
var snoopy = new Dog("Snoopy");
var marley = new Dog("Marley");
var megan = new Dog("Megan");
var catHouse = new CatHouse(fluffy, miu, snuffles);
var dogHouse = new DogHouse(snoopy, marley, megan);
var animalCity = new AnimalCity(catHouse, dogHouse);
foreach (var sound in animalCity.CitySounds()) {
Console.WriteLine(sound);
}
}
}
Output:
Miu: meow
Snoopy: woof
Snuffles: meow
Fluffy: meow
Marley: woof
Megan: woof
Notes:
I added names so it's clear that the method references carry their owner's data with them, for those unfamiliar with delegates.
The required using statements for this code are System, System.Collections.Generic, and System.Linq.
You can try it here: https://dotnetfiddle.net/6qkHL3#
A version that makes GeneralAnimalHouse a subclass of AnimalHouse<Animal> can be found here: https://dotnetfiddle.net/XS0ljg
I was using generic types in C# and I am new to using generic types. So, right now I am stuck with a problem. I have some classes like these:
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T>
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
//What will be the syntax of declaring this method
//The syntax of the following method is wrong and incomplete.
//It's there just to give an idea about whai i want to do.
public void MyMethod<T>()
where T : BaseClass<..what to write..>
{
}
}
My question is what will be the correct syntax of declaring MyMethod if I want to call MyMethod like this:
MyMethod<ChildClass1>();
If I understood correctly, you try to filter "MyMethod" so that T is a class of type "ChildClass ...".
You can add a generic parameter to your function like this:
public void MyMethod<T, U>()
where T : BaseClass<U>
{
}
But then you have to call MyMethod in that way.
MyMethod<ChildClass1, MyModel1>();
So it's quite complicated to use.
Another solution is to create a new "blank" class :
public abstract class Base // mark it as abstract if you don't need to use it in your code
{
}
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T> : Base //The class inherits the new class
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
public void MyMethod<T>()
where T : Base
{
}
}
You've forgotten to mention the return type and adding <T> after the class name. For example, if the return type is void, you could declare the method as:
public void MyMethod<T>()
where T : BaseClass<T>
{
}
This will work (by which I mean it compiles)
public void MyMethod<T>()
where T : BaseClass<MyModel1>
{ }
so does this:
public void MyMethod<T>()
where T : ChildClass1
{ }
Further edit after reading your comment...
You can do this:
public class AnotherClass<TBaseClass, TModel> where TBaseClass : BaseClass<TModel>
{
public void MyMethod(TBaseClass input)
{ }
}
I have a term for this, hopefully non-offensive. I call it The Generic Rabbit Hole of Madness. It's what happens when we try to combine generics and inheritance so that one set of classes can accomplish a broad set of goals that become increasingly confusing, and we solve it by adding more generic parameters and more generic classes.
You reach the bottom of the hole if you
- use <dynamic>
- check to see what the actual type is using GetType(), typeof, or is
- get it to compile but can't remember what it's supposed to do
I have the following classes
public abstract class BaseViewPresenter { }
public abstract class BaseView<T> : UserControl
where T : BaseViewPresenter { }
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> { }
I have a method that looks like this (simplified)
public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
// Correctly creates BaseView object
var control = Activator.CreateInstance(viewType);
// Fails to cast as BaseView<BaseViewPresenter> so returns null
return control as BaseView<BaseViewPresenter>;
}
When I call this using an instances of LoginPresenter
var login = new LoginPresenter();
var ctl = Resolve(login);
The line Activator.CreateInstance(viewType) correctly resolves into a new instances of my LoginView, however control as BaseView<BaseViewPresenter> can't do the cast correctly so returns null.
Is there a way to correctly cast the control into BaseView<BaseViewPresenter> without using specific type generics?
Since LoginView inherits from BaseView<LoginPresenter>, and LoginPresenter inherits from BaseViewPresenter, I would assume there's a way to convert LoginView to BaseView<BaseViewPresenter>.
I am stuck with using .Net 3.5
This is a very frequently asked question. Let's rename your types:
abstract class Fruit { } // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // was LoginView
Your question now is:
I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.
No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.
Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:
The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.
Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
I accepted Eric's answer since it provides a great explanation of why what I wanted wasn't possible, but I also thought I'd share my solution in case anyone else runs into this same problem.
I removed the generic type parameter from my original BaseView class, and created a 2nd version of the BaseView class that included the generic type parameter and specifics for it.
The first version is used by my .Resolve() method or other code that doesn't care about the specific types, and the second version is used by any code that does care, such as the implentation of a BaseView
Here's an example of how my code ended up looking
// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl
{
public BaseViewPresenter Presenter { get; set; }
}
public abstract class BaseView<T> : BaseView
where T : BaseViewPresenter
{
public new T Presenter
{
get { return base.Presenter as T; }
set { base.Presenter = value; }
}
}
// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter>
{
// Can now call things like Presenter.LoginPresenterMethod()
}
// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
BaseView view = Activator.CreateInstance(viewType) as BaseView;
view.Presenter = presenter;
return view;
}
You're expecting to treat the type as being covariant with respect to the generic argument. Classes can never be covariant; you'd need to use an interface rather than (or in addition to) an abstract class to make it covariant with respect to T. You'd also need to be using C# 4.0.
My usual solution to this problem is to create an intermediary class that has access to the type-parametric class's methods through delegates. Fields can also be accessed through getters/setters.
The general pattern goes:
public abstract class Super {}
public abstract class MyAbstractType<T> where T : Super {
public MyGeneralType AsGeneralType() {
return MyGeneralType.Create(this);
}
// Depending on the context, an implicit cast operator might make things
// look nicer, though it might be too subtle to some tastes.
public static implicit operator MyGeneralType(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
public int field;
public void MyMethod1() {}
public void MyMethod2(int argument) {}
public abstract bool MyMethod3(string argument);
}
public delegate T Getter<T>();
public delegate void Setter<T>(T value);
public delegate void MyMethod1Del();
public delegate void MyMethod2Del(int argument);
public delegate bool MyMethod3Del(string argument);
public class MyGeneralType {
public Getter<int> FieldGetter;
public Setter<int> FieldSetter;
public MyMethod1Del MyMethod1;
public MyMethod2Del MyMethod2;
public MyMethod3Del MyMethod3;
public static MyGeneralType Create<T>(MyAbstractType<T> t) where T : Super {
var g = new MyGeneralType();
g.FieldGetter = delegate { return t.field; };
g.FieldSetter = value => { t.field = value; };
g.MyMethod1 = t.MyMethod1;
g.MyMethod2 = t.MyMethod2;
g.MyMethod3 = t.MyMethod3;
return g;
}
public int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
The above exemplifies getting all the methods and fields but normally I only need a few of them. This is a general solution to the problem and one could feasibly write a tool to generate these intermediary classes automatically, which I might at some point.
Try it here: https://dotnetfiddle.net/tLkmgR
Note that this is enough for all my cases, but you can be extra hacky with this:
public abstract class MyAbstractType<T> where T : Super {
// ... Same everything else ...
// data fields must become abstract getters/setters, unfortunate
public abstract int field {
get;
set;
}
public static implicit operator MyAbstractType<Super>(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
}
public class MyGeneralType : MyAbstractType<Super> {
// ... same constructors and setter/getter
// fields but only keep method fields
// that contain the method references for
// implementations of abstract classes,
// and rename them not to clash with the
// actual method names ...
public MyMethod3Del myMethod3Ref;
// Implement abstract methods by calling the corresponding
// method references.
public override bool MyMethod3(string argument) {
return myMethod3Ref(argument);
}
// Same getters/setters but with override keyword
public override int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
And there you go, now you can literally cast a MyAbstractType<Sub> where Sub : Super to a MyAbstractType<Super>, although it's no longer the same object anymore, but it does retain the same methods and data, it's sort of a complex pointer.
public class Sub : Super {}
public class MySubType : MyAbstractType<Sub> {
public int _field;
public override int field {
get { return _field; }
set { _field = value; }
}
public override bool MyMethod3(string argument) {
Console.WriteLine("hello " + argument);
return argument == "world";
}
}
public class MainClass {
public static void Main() {
MyAbstractType<Sub> sub = new MyAbstractType<Sub>();
MyAbstractType<Super> super = sub;
super.MyMethod3("hello"); // calls sub.MyMethod3();
super.field = 10; // sets sub.field
}
}
This isn't as good in my opinion, the other version of MyGeneralType is a more straighforward layer over the concrete types, plus it doesn't require rewriting the data fields, but it does actually answer the question, technically. Try it here: https://dotnetfiddle.net/S3r3ke
Example
Using these abstract classes:
public abstract class Animal {
public string name;
public Animal(string name) {
this.name = name;
}
public abstract string Sound();
}
public abstract class AnimalHouse<T> where T : Animal {
List<T> animals;
public AnimalHouse(T[] animals) {
this.animals = animals.ToList();
}
public static implicit operator GeneralAnimalHouse(AnimalHouse<T> house) {
return GeneralAnimalHouse.Create(house);
}
public List<string> HouseSounds() {
return animals.Select(animal => animal.Sound()).ToList();
}
}
We make this "general" variant:
public delegate List<string> HouseSoundsDel();
public class GeneralAnimalHouse {
public HouseSoundsDel HouseSounds;
public static GeneralAnimalHouse Create<T>(AnimalHouse<T> house) where T : Animal {
var general = new GeneralAnimalHouse();
general.HouseSounds = house.HouseSounds;
return general;
}
}
And finally with these inheritors:
public class Dog : Animal {
public Dog(string name) : base(name) {}
public override string Sound() {
return name + ": woof";
}
}
public class Cat : Animal {
public Cat(string name) : base(name) {}
public override string Sound() {
return name + ": meow";
}
}
public class DogHouse : AnimalHouse<Dog> {
public DogHouse(params Dog[] dogs) : base(dogs) {}
}
public class CatHouse : AnimalHouse<Cat> {
public CatHouse(params Cat[] cats) : base(cats) {}
}
We use it like this:
public class AnimalCity {
List<GeneralAnimalHouse> houses;
public AnimalCity(params GeneralAnimalHouse[] houses) {
this.houses = houses.ToList();
}
public List<string> CitySounds() {
var random = new Random();
return houses.SelectMany(house => house.HouseSounds())
.OrderBy(x => random.Next())
.ToList();
}
}
public class MainClass {
public static void Main() {
var fluffy = new Cat("Fluffy");
var miu = new Cat("Miu");
var snuffles = new Cat("Snuffles");
var snoopy = new Dog("Snoopy");
var marley = new Dog("Marley");
var megan = new Dog("Megan");
var catHouse = new CatHouse(fluffy, miu, snuffles);
var dogHouse = new DogHouse(snoopy, marley, megan);
var animalCity = new AnimalCity(catHouse, dogHouse);
foreach (var sound in animalCity.CitySounds()) {
Console.WriteLine(sound);
}
}
}
Output:
Miu: meow
Snoopy: woof
Snuffles: meow
Fluffy: meow
Marley: woof
Megan: woof
Notes:
I added names so it's clear that the method references carry their owner's data with them, for those unfamiliar with delegates.
The required using statements for this code are System, System.Collections.Generic, and System.Linq.
You can try it here: https://dotnetfiddle.net/6qkHL3#
A version that makes GeneralAnimalHouse a subclass of AnimalHouse<Animal> can be found here: https://dotnetfiddle.net/XS0ljg
Consider the following classes :
public abstract class Animal
{
public abstract Animal GiveBirth();
}
public class Monkey : Animal
{
public override Animal GiveBirth()
{
return new Monkey();
}
}
public class Snake : Animal
{
public override Animal GiveBirth()
{
return new Snake();
}
}
//That one doesnt makes sense.
public class WeirdHuman: Animal
{
public override Animal GiveBirth()
{
return new Monkey();
}
}
I'm searching a way to enforce the return types of the overrided GiveBirth method so that it always returns the actual class type, so that no WeirdHuman can give birth to a Monkey.
I feel like the answer is about generic types, but I can't see how I can do that.
Exemple of the expected result :
public abstract class Animal
{
public abstract /*here a way to specify concrete type*/ GiveBirth();
}
public class Monkey : Animal
{
public override Monkey GiveBirth() //Must returns an actual Monkey
{
return new Monkey();
}
}
"Absolutely impossible" may be an answer, if clearly explained.
This is co-variant returns and is not supported by C#. I lament this daily. The best you can hope to do to get around it is to use a generic return type and specify a where condition on the generic type, but this can also cause you to run in to other issues down the road with matching generic parameter requirements.
public abstract class Animal<TBirthType> where TBirthType : Animal<TBirthType>
{
public abstract TBirthType GiveBirth();
}
public class Monkey<TBirthType> : Animal<TBirthType> where TBirthType : Monkey<TBirthType>
{
public override TBirthType GiveBirth()
{
return new Monkey<Monkey>();
}
}
Alternately, if you don't need any further inheritance, you can close the generic.
public class Monkey : Animal<Monkey>
{
public override Monkey GiveBirth()
{
return new Monkey();
}
}
Note that covariance alone is still not enough to ensure that no misbehaving derived type can be formed, but it will allow for the type of the return to be specified as the type being used. There still wouldn't be a way to lock it down from the abstract class though. You could perhaps manage a runtime check via reflection from a method implemented at the base level that would check type at runtime, but this could also be very messy.
As far as I know, there is no clean way to support this purely in a single class hierarchy. Using recurring generic type parameters e.g.
public class Animal<T> where T : Animal<T> { }
may be acceptable if you control the entire hierarchy, and can therefore rule out classes like
public class WierdHuman<Monkey> { }
What you really want is something like Haskell's typeclasses, where you can abstract over the concrete type of the class itself. The closest you can get in C# is to define a surrogate object which implements the required functionality, and then pass that around wherever you require it.
In your case, this means creating an interface for giving birth, and implementing it for each concrete animal type.
Your methods which require this functionality then need an extra parameter for the 'typeclass instance'. These methods can restrict the generic animal type to be the same:
public interface ISpawn<T> where T : Animal
{
public T GiveBirth();
}
public void Populate<T>(T parent, ISpawn<T> spawn) where T : Animal
{
}
You can do something like this, which forces the implementers of Animal<T> to implement an Animal<T> GiveBirth() method which returns the same type as the type parameter, which itself is constrained to be a kind of animal.
That's not quite what you want, but just so you can see:
public abstract class Animal<T> where T: Animal<T>
{
public abstract Animal<T> GiveBirth();
}
public class Monkey: Animal<Monkey>
{
public override Animal<Monkey> GiveBirth()
{
return new Monkey();
}
}
public class Snake: Animal<Snake>
{
public override Animal<Snake> GiveBirth()
{
return new Snake();
}
}
public class WeirdHuman: Animal<WeirdHuman>
{
public override Animal<WeirdHuman> GiveBirth()
{
return new Monkey(); // Won't compile of course.
}
}
If you comment out the public override Animal<Monkey> GiveBirth() methods, you'll see that the compiler complains and says something like:
Error 1 'ConsoleApplication1.Monkey' does not implement inherited abstract member 'ConsoleApplication1.Animal.GiveBirth()'
Unfortunately, you must declare the classes using the SomeKindOfAnimal: Animal<SomeKindOfAnimal> syntax, but maybe this will work for you.
(Also see this thread.)
Alas, this doesn't quite work because it allows you to do this:
public class Monkey: Animal<WeirdHuman>
{
public override Animal<WeirdHuman> GiveBirth()
{
return new WeirdHuman();
}
}
In other words, it constrains the type parameter to be a kind of animal, and it also constrains the return type of GiveBirth() to be the same as the type parameter; but that's all it does. In some cases this is enough, but probably not for your purposes.
Still, perhaps this approach is worth knowing about.
If you have an situation where your base class cannot be generic for various reasons, this method might be useful:
abstract class Animal {
}
interface ICanGiveBirth<T> {
T GiveBirth();
}
static class CanGiveBirthHelper {
public static T GiveBirth<T>(this T v) where T: ICanGiveBirth<T> => v.GiveBirth();
}
class Monkey : Animal, ICanGiveBirth<Monkey> {
public Monkey GiveBirth() {
throw new NotImplementedException();
}
}
class Snake : Animal, ICanGiveBirth<Snake> {
public Snake GiveBirth() {
throw new NotImplementedException();
}
}
If you are unable to add interface to your sub classes, and still unable to add generics to the Base type this method might be useful:
(Unfortunately you cannot make the GiveBirthImpl protected, since the helper class is not allowed to be inside the base class)
abstract class Animal {
public abstract T GiveBirthImpl<T>() where T:Animal;
}
static class CanGiveBirthHelper {
public static T GiveBirth<T>(this T v) where T: Animal => v.GiveBirthImpl<T>();
}
class Monkey : Animal {
public override T GiveBirthImpl<T>() {
throw new NotImplementedException();
}
}
class Snake : Animal {
public override T GiveBirthImpl<T>() {
throw new NotImplementedException();
}
}
In both cases, this will work as expected:
class Tester
{
Monkey TestIt() => new Monkey().GiveBirth();
}