Using base objects as parameters in a generic function - c#

I'm trying to implement a helper method using generics (C# / 3.5)
I've a nice structure of classes, with base classes like so:
public class SomeNiceObject : ObjectBase
{
public string Field1{ get; set; }
}
public class CollectionBase<ObjectBase>()
{
public bool ReadAllFromDatabase();
}
public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{
}
And I wish to retreive collection using a generic method like so:
public class DAL
{
public SomeNiceObjectCollection Read()
{
return ReadFromDB<SomeNiceObjectCollection>();
}
T ReadFromDB<T>() where T : CollectionBase<ObjectBase>, new()
{
T col = new T();
col.ReadAllFromDatabase();
return col;
}
}
This doesn't build, with
Error 66 The type 'SomeNiceObjectCollection' cannot be used as type parameter 'T' in the generic type or method 'ReadFromDB<T>'. There is no implicit reference conversion from 'SomeNiceObjectCollection' to 'CollectionBase<ObjectBase>'.
The SomeNiceObjectCollection object IS a CollectionBase, a CollectionBase to be exact. So how I can get this to work?

C# doesn't support casting between list types (covariance).
Your best bet to support this pattern would be to introduce an interface for the ReadAllFromDatabase method so you are not relying on a generic collection:
public class SomeNiceObject : ObjectBase
{
public string Field1{ get; set; }
}
public interface IFromDatabase
{
bool ReadAllFromDatabase();
}
public class CollectionBase<ObjectBase>() : IFromDatabase
{
public bool ReadAllFromDatabase();
}
public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{
}
public class DAL
{
public SomeNiceObjectCollection Read()
{
return ReadFromDB<SomeNiceObjectCollection>();
}
T ReadFromDB<T>() where T : IFromDatabase, new()
{
T col = new T();
col.ReadAllFromDatabase();
return col;
}
}

In C# 3.0 this is not possible, but with C# and .NET 4.0 with covariance and contravariance, this might be possible.
Think about it, you're taking a collection containing a derived object, and trying to temporarily treat it as a collection of the base object. If this was allowed, you could insert base objects into the list, which would not be of the derived object.
Here, an example:
List<String> l = new List<String>();
List<Object> o = l;
l.Add(10); // 10 will be boxed to an Object, but it is not a String!

Related

Casting to a generic interface [duplicate]

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

Cast unknown object to generic interface of interface (from initially explicit generic type of generic collection type of type)

Basically I got those sample classes:
public interface IHasParts<TCollectionType> : where TCollectionType : ICollection
{
TCollectionType Parts { get; set; }
}
public class CarPart
{
//...
}
public class Car : IHasParts<List<CarPart>>
{
public List<CarPart> Parts { get; set; }
//...
}
Yes, I need to use an generic interface of ICollection here, because classes that implement IHasParts need different list types of Parts based on some hard programmed conditions.
Now I get an unknown object of i.e. Car and I need to cast it to the highest parent that still has the Parts property available:
Car c = new Car() {
Parts = new List<CarPart>() {
// ...
}
};
object o = (object)c;
int partsCount = ((IHasParts<ICollection>)o).Parts.Count; // InvalidCastException
How can I do that? DotNetFiddle
This is a variance issue.
You're assuming that, because List<T> is a subtype of ICollection, then IHasParts<List<T>> must too be a subtype of IHasParts<ICollection>. It doesn't.
If you want IHasParts<A> to be a subtype of IHasParts<B> where A is a subtype of B, then you need to make IHasParts covariant in its type parameter T (using the out keyword).
public interface IHasParts<out TCollectionType> : where TCollectionType : ICollection
{
TCollectionType Parts { get; }
}
For a type to be covariant, T can only be used in covariant positions: method return types, get-only property types and get-only indexers.
It can no longer be used in contravariant positions: method arguments, property/indexer setters.
If you define your Car class with ICollection instead of List<CarPart>, then works:
public class Car : IHasParts<ICollection>
{
public ICollection Parts { get; set; }
}
You can still initialize your Parts with a List<CarPart>
Add an abstract class to take care of specifying the ICollection type. Declare your code something like this:
public interface IHasParts
{
ICollection Parts { get; }
}
public abstract class HasParts<TCollectionType, TPartType> : IHasParts where TCollectionType : ICollection
{
public TCollectionType Parts;
ICollection IHasParts.Parts { get { return this.Parts; } }
}
public class CarPart
{
//...
}
public class Car : HasParts<List<CarPart>, CarPart>
{
protected void AddParts()
{
this.Parts.Add(new CarPart());
}
}
UPDATE:
Here is an updated version of your DotNetFiddle: https://dotnetfiddle.net/O3JZgc

Casting generic class to dynamic type

I have a generic class that I want to cast to a dynamic generic, but I get a Cannot convert type MyGeneric1<MyTypedClass1> to MyGeneric1<dynamic> error message. Is this kind of cast to dynamic possible, and if so then please explain.
Here is where I try to cast a typed MyGeneric1 generic class into a dynamic MyGeneric1.
public static class Extensions
{
public static MyGeneric1<dynamic> ToDynamic(this MyGeneric1<MyTypedClass1> myObj1)
{
return (MyGeneric1<dynamic>)myObj1;
}
}
The MyGeneric1 class is defined like so:
public class MyGeneric1<T> : DynamicObject { // Code here ... }
The MyTypedClass1 class is defined like so:
public class MyTypedClass1: DynamicObject { // Code here ... }
MyTypedClass1 is assignable to dynamic, as it inherits from it. But you cannot simply cast generic classes, when they have different generic arguments, even when arguments themselves are valid for assigning (as MyTypedClass1 and dynamic ).
But, you can create new instance with proper generic type and assign value for it:
public class MyTypedClass1 : DynamicObject
{
public string SomeProperty { get; set; }
}
public class MyGeneric<T> : DynamicObject
{
// just some property to get the idea
public T Value { get; set; }
}
public static class MyGenericExtensions
{
public static MyGeneric<dynamic> ConveretGeneric(this MyGeneric<MyTypedClass1> argument)
{
return new MyGeneric<dynamic>()
{
// here you need to assign all needed properties
Value = argument.Value
};
}
}

Generic objects in c#

i have a litte problem and i need some help :)
For example i have a simle abstract class
public abstract class BaseDefinition
{
public int Id { get;set; }
public string Name { get;set; }
}
and other base class
public abstract class BaseParentClass
{
public string Name { get;set; }
public string Schema { get;set; }
}
and first generic abstract class
public abstrac class BaseParentClass<T> :
BaseParentClass where T : BaseDefinition
{
public IList<T> Objects {get;set;}
}
and first implementations
public class ClassADefintion : BaseDefinition
{
public bool IsChanged {get;set;}
}
public class ClassAObject : BaseParentClass<ClassADefinition>
{
public bool OtherField {get;set;}
}
public class ClassBDefintion : BaseDefinition
{
public bool IsBBBChanged {get;set;}
}
public class ClassBObject : BaseParentClass<ClassBDefinition>
{
public bool OtherBBBBField {get;set;}
}
Sorry for class name, but I can't create anything better (it's only example)
As We see, now is all OK :).
I have some methods who returns a IEnumerable of generic implementation
IEnumerable<ClassBObject> ClassBObjectCollection;
IEnumerable<ClassAObject> ClassAObjectCollection;
Now i must create a method, who can take a generic objects in IEnumerable
public void DoWork(IEnumerable<BaseParentClass<BaseDefinition>> objects)
{
foreach(var baseObj in objects)
{
foreach(var baseDef in baseObj.Objects)
{
// do some work
}
}
}
How i remember BaseObject<BaseDefinition> != ClassAObject, but compiler doesn't put on screen any errors. I remember in .NET in generic interface We can use IN and OUT T, so i try make this
public interface IBaseParentClass<out T> where T : BaseDefinition
{
IList<T> Objects {get;set;}
}
Yup, You can't make a List of <out T>. Somebody have any idea for this problem ?
I can get this fields values by reflection, but i have abstract class and interface so i think is a better way.
I don't have a compiler at hand, but I think it should be possible to rewrite DoWork as such:
public void DoWork<T>(IEnumerable<BaseObject<T>> objects)
where T : BaseDefinition
{
foreach(var baseObj in objects)
{
foreach(var baseDef in baseObj.Objects)
{
// do some work
}
}
}
I am not sure whether the compiler will be able to infer T for you, try it out.
Another possibility may be that if you enumerate those objects anyway, to make Objects of Type IEnumerable(Of T).

C# Derived Type to Generic List as Parameter

I am trying to do the following in C# 4.0:
I have a Base Class and 2 derived classes
public class Base {}
public class DerivedClass1 : Base {}
public class DerivedClass2 : Base {}
I want to do something like this, but it doesn't work.
How to I tell a Generic List to accept a Base Class and the derived classes of the base class.
public class Class_1
{
public Class_1()
{
List<DerivedClass2> list = new List<DerivedClass2>();
new Class_2(list);
}
}
public class Class_2
{
public Class_2(List<Base> list)
{
}
}
In Java I can do something like this
public class Class_2
{
public Class_2(List<? extends Base> list)
{
}
}
Does something like that exists in C#
I hope my question is clear, its just about the generics of the List.
Thanks a lot in Advance :)
General case:
function Foo<T>(List<T> list) where T : Base {
...
}
plus for interfaces and delegates, C# allows co/contravariance.
For e.g. IEnumerable<T> and IList<T>, your code will therefore work! Note that if this was allowed for List<T>s, you could insert a Derived1 into a list of Derived2s by using the common base class, which would break type safety. So simply stick to the above, readonly interfaces.
I think you mean either:
// Define other methods and classes here
public class Class_1
{
public Class_1()
{
List<DerivedClass2> list = new List<DerivedClass2>();
new Class_2<DerivedClass2>(list);
}
}
public class Class_2<T> where T : Base
{
public Class_2(List<T> list)
{
}
}
Or, if you want the constructor to be generic, and not the class:
// Define other methods and classes here
public class Class_1
{
public Class_1()
{
List<DerivedClass2> list = new List<DerivedClass2>();
Class_2.Create(list);
}
}
public class Class_2
{
public static Class_2 Create<T>(List<T> list) where T : Base
{
// Stuff
return new Class_2(/*Stuff*/);
}
public Class_2()
{
}
}

Categories

Resources