Duplicate
In C#, why can’t a List object be stored in a List variable
Here is my code:
public class Base
{
protected BindingList<SampleBase> m_samples;
public Base() { }
}
public class Derived : Base
{
public Derived()
{
m_samples = new BindingList<SampleDerived>();
}
}
SampleDerived is derived from SampleBase
According to the inheritance logic, I should be able to do this. However, it doesn't compile - the error says that SampleBase can not be be implicitly converted to SampleDerived type. What gives?
I am using c# 2.0
You're trying to use covariance, which is not supported by C# 3.0 and earlier (but will be in C# 4.0). You can still add objects of type SampleDerived into m_samples, but the list's generic type will need to be SampleBase.
Edit: So Pavel is right, C# 4.0 doesn't actually help with this. It would if m_sample were defined as IBindingList<SampleBase> using (fictional) covariant interface IBindingList<out T>.
I can understand why you would think that but generics don't work that way. :(
BindingList<SampleDerived> does not actually derive from BindingList<SampleBase>
A BindingList<SampleDerived> is not a BindingList<SampleBase> -- you can add a SampleBase to the latter, but not to the former.
Generics cannot be casted.
You can cast List<MyClass> to IList<MyClass> or even IList, but this would be illegal:
List<Object> = new List<MyClass>();
Most likely you must simply create the list instance in your base class, and freely use it in derived.
public class Base
{
protected BindingList<SampleBase> m_samples = new BindingList<Derived>();
public Base() { }
}
public class Derived : Base
{
public FwdRunData()
{
m_samples.Add(new Derived>());
}
}
This type of generic variance is not supported in C#2 or 3. It will be supported in C#4. (See comment.) Eric Lippert has a series of blog posts on this subject that goes into enough detail to kill any unwary developer. :)
The people pointing you to Eric Lippert's excellent posts on variance are right, but here's a short example showing what would go wrong. I've just added a new method to the base class and I'm using another derived sample class. What would happen when the BreakDerived method is called on an instance of your original Derived class? You can't add an instance of SampleDerived2 to the BindingList<SampledDerived>.
public class Base {
protected BindingList<SampleBase> m_samples;
public Base() { }
public BreakDerived() { m_samples.Add(new SampleDerived2()); }
}
public class Derived : Base {
public Derived() { m_samples = new BindingList<SampledDerived>(); }
}
Related
I know this is old, yet I am still not very good with understanding those problems. Can anyone tell me why the following does not work (throws a runtime exception about casting)?
public abstract class EntityBase { }
public class MyEntity : EntityBase { }
public abstract class RepositoryBase<T> where T : EntityBase { }
public class MyEntityRepository : RepositoryBase<MyEntity> { }
And now the casting line:
MyEntityRepository myEntityRepo = GetMyEntityRepo(); // whatever
RepositoryBase<EntityBase> baseRepo = (RepositoryBase<EntityBase>)myEntityRepo;
So, can anyone explain how is this invalid? And, I you are not in the mood to explain - is there a line of code I can use to actually do this cast?
RepositoryBase<EntityBase> is not a base class of MyEntityRepository. You're looking for generic variance which exists in C# to a limited extent, but wouldn't apply here.
Suppose your RepositoryBase<T> class had a method like this:
void Add(T entity) { ... }
Now consider:
MyEntityRepository myEntityRepo = GetMyEntityRepo(); // whatever
RepositoryBase<EntityBase> baseRepo = (RepositoryBase<EntityBase>)myEntityRepo;
baseRepo.Add(new OtherEntity(...));
Now you've added a different kind of entity to a MyEntityRepository... and that can't be right.
Basically, generic variance is only safe in certain situations. In particular generic covariance (which is what you're describing here) is only safe when you only ever get values "out" of the API; generic contravariance (which works the other way round) is only safe when you only ever put values "into" the API (e.g. a general comparison which can compare any two shapes by area can be considered as a comparison of squares).
In C# 4 this is available for generic interfaces and generic delegates, not classes - and only with reference types. See MSDN for further information, read <plug>read C# in Depth, 2nd edition, chapter 13</plug> or Eric Lippert's blog series on the topic. Also, I gave a one hour talk about this at NDC in July 2010 - the video is available here.
Whenever someone asks this question, I try to take their example and translate it to something using more well-known classes that is obviously illegal (this is what Jon Skeet has done in his answer; but I'm taking it a step further by performing this translation).
Let's replace MyEntityRepository with MyStringList, like this:
class MyStringList : List<string> { }
Now, you seem to want MyEntityRepository to be castable to RepositoryBase<EntityBase>, the reasoning being that this ought to be possible since MyEntity derives from EntityBase.
But string derives from object, doesn't it? So by this logic we should be able to cast a MyStringList to a List<object>.
Let's see what can happen if we allow that...
var strings = new MyStringList();
strings.Add("Hello");
strings.Add("Goodbye");
var objects = (List<object>)strings;
objects.Add(new Random());
foreach (string s in strings)
{
Console.WriteLine("Length of string: {0}", s.Length);
}
Uh-oh. Suddenly we're enumerating over a List<string> and we come upon a Random object. That's not good.
Hopefully this makes the issue a bit easier to understand.
This requires covariance or contravariance, whose support is limited in .Net, and cannot be used on abstract classes. You can use variance on interfaces though, so a possible solution to your problem is to create an IRepository which you use in place of the abstract class.
public interface IRepository<out T> where T : EntityBase { //or "in" depending on the items.
}
public abstract class RepositoryBase<T> : IRepository<T> where T : EntityBase {
}
public class MyEntityRepository : RepositoryBase<MyEntity> {
}
...
IRepository<EntityBase> baseRepo = (IRepository<EntityBase>)myEntityRepo;
When working with generics if I have for example a class:
class Foo<T> where T:Cheese
{
}
and then 2 derived classes
class FooDerivedBlue:Foo<BlueCheese>
{
}
class FooDerivedWhite:Foo<WhiteCheese>
{
}
where BlueChesse and WhiteCheese inherit from chesse.
Now there is another class, that will conditionally use FooDerivedBlue or FooDerivedWhite.
The class should have a property like
public Foo<Cheese> Foo {get;set;}
so I can set it to the FooDerivedXXX I need at runtime.
When doing this an trying to set Foo=new FooDerivedWhite() the compiler will complain, since FooDerivedWhite cant be converted to Foo<cheese>.
A more practical example:
If I have a
ArticleRepository<T>
AssemblyArticleRepository:ArticleRepository<AssemblyArticle>
ProductionArticleRepository:ArticleRepository<ProductionArticle>.
ProductionArticle and AssemblyArticle inherit from Article.
Both specific repositories inherit from ArticleRepository and have a lot of common logic. There are certain parts I need only access to the logic they shared (for example adding a new item or deleting it) and in order to avoid duplicate code, I want to instantiate the proper repo and pass it.
For example, I could have an ArticleService, which I pass a type and it instantiates the right repository. Instead, I would need to have a service for each Article type. (??- with my actual knowledge)
Which is the way to solve it in .NET? Or maybe I am facing the problem/writing my code in a wrong way?
Update Here a gist with the concrete problem:
https://gist.github.com/rgomez90/17ec21a1a371be6d78a53a4072938f7f
There are a few ways to deal with this, but the most straightforward is probably to make your "other class" also have a generic type parameter that describes what kind of cheese it operates on. Then all the types can be statically correct.
public abstract class Cheese { }
public class BlueCheese : Cheese { }
public abstract class CheeseTool<T> where T:Cheese { }
public class BlueCheeseTool : CheeseTool<BlueCheese> { }
public class CheeseEater<T> where T : Cheese {
public T Cheese;
public CheeseTool<T> Tool;
}
Then all typing is statically correct:
CheeseEater<BlueCheese> eater = new CheeseEater<BlueCheese>();
eater.Cheese = new BlueCheese();
eater.Tool = new BlueCheeseTool();
More complicated solutions might involve explicit casts and type factories, but simplest is best if it does the job.
The Problem
It's something I came across a while back and was able to work around it somehow. But now it came back, feeding on my curiosity - and I'd love to have a definite answer.
Basically, I have a generic dgv BaseGridView<T> : DataGridView where T : class. Constructed types based on the BaseGridView (such as InvoiceGridView : BaseGridView<Invoice>) are later used in the application to display different business objects using the shared functionality provided by BaseGridView (like virtual mode, buttons, etc.).
It now became necessary to create a user control that references those constructed types to control some of the shared functionality (eg. filtering) from BaseGridView. I was therefore hoping to create a public property on the user control that would enable me to attach it to any BaseGridView in Designer/code: public BaseGridView<T> MyGridView { get; set; }. The trouble is, it doesn't work :-) When compiled, I get the following message:
The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)
Solutions?
I realise I could extract the shared functionality to an interface, mark BaseGridView as implementing that interface, and then refer to the created interface in my uesr control.
But I'm curious if there exists some arcane C# command/syntax that would help me achieve what I want - without polluting my solution with an interface I don't really need :-)
EDIT: For reference, I did try this innocent workaround: BaseGridView<object> MyGridView { get; set; }, and... it still isn't the answer: Cannot implicitly convert type 'InvoiceGridView' to 'BaseGridView<object>'.
Partial success (edit 2)
Ok, because covariance is only supported on interfaces, I admitted defeat and defined an interface (only showing some of it):
public interface IBaseGridView<out T> where T : class
{
bool ScrollTo(Predicate<T> criteria);
bool ScrollTo(T object);
}
I am now able to cast my beloved InvoiceGridView to an IBaseGridView<object> - which is awesome and I'm a happy boy again :-) However, the second ScrollTo is giving me trouble upon compilation:
Invalid variance: The type parameter 'T' must be contravariantly valid on 'GeParts.Controls.IBaseGridView.ScrollTo(T)'. 'T' is covariant.
I'm now having to modify the signature to ScrollTo(object o) - which isn't ideal but gets the job done. What suprised me was that the compiler complained about the second ScrollTo yet was happy with the first one. So it seems that one isn't allowed to pass instances of an out T, but using the type itself (eg. in Predicate<T>) is fine? Seems rather picky...
Since you wrote
But I'm curious if there exists some arcane C# command/syntax that would help me achieve what I want
I'd like to add that C# 4.0 makes it possible to substitute derived types for a base type using < out T > for covariance. So you could do
public BaseGridView<Object> MyGridView { get; set; }
So you get a well known type but you can return whatever BaseGridView you want. The only catch is unfortunately that covariance is only allowed on interfaces! :(
C# doesn't support generic properties to my knowledge. Your options are either to create generic methods or to make the generic type part of your class definition.
For example:
public BaseGridView<T> GetMyGridView<T>() { ... }
public void SetMyGridView<T>(T gridView) { ... }
or
class MyClass<T> {
public BaseGridView<T> MyGridView { get; set; }
}
The following would probably work:
public BaseGridView<T> MyGridView<T> { get; set; }
The problem with your original answer is that the type parameter has to appear on the method or class declaration, not just on the return value.
Note that the compiler cannot infer generic types from return values, so you'll be required to specify T in every call to MyGridView.
I just tried whipping together some code and it works fine for me:
public class A<T> where T : class
{
public virtual A<T> ARef
{
get { return default(A<T>); }
}
}
public class B : A<B>
{
public override A<B> ARef
{
get
{
return base.ARef;
}
}
}
Shouldn't it be like this:
public BaseGridView MyGridView { get; set; }
public BaseGridView<T> GetMyGridView<T> { return whatever; }
public void SetMyGridView<T>( BaseGridView<T> bgv) { whatever = bgv; }
??
Edited. Matthew is right, Properties may not be generic. You would have to use a getter/setter.
I have a container class that has a generic parameter which is constrained to some base class. The type supplied to the generic is a sub of the base class constraint. The sub class uses method hiding (new) to change the behavior of a method from the base class (no, I can't make it virtual as it is not my code). My problem is that the 'new' methods do not get called, the compiler seems to consider the supplied type to be the base class, not the sub, as if I had upcast it to the base.
Clearly I am misunderstanding something fundamental here. I thought that the generic where T: xxx was a constraint, not an upcast type.
This sample code basically demonstrates what I'm talking about.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericPartialTest
{
class ContextBase
{
public string GetValue()
{
return "I am Context Base: " + this.GetType().Name;
}
public string GetOtherValue()
{
return "I am Context Base: " + this.GetType().Name;
}
}
partial class ContextSub : ContextBase
{
public new string GetValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
partial class ContextSub
{
public new string GetOtherValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
class Container<T> where T: ContextBase, new()
{
private T _context = new T();
public string GetValue()
{
return this._context.GetValue();
}
public string GetOtherValue()
{
return this._context.GetOtherValue();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Simple");
ContextBase myBase = new ContextBase();
ContextSub mySub = new ContextSub();
Console.WriteLine(myBase.GetValue());
Console.WriteLine(myBase.GetOtherValue());
Console.WriteLine(mySub.GetValue());
Console.WriteLine(mySub.GetOtherValue());
Console.WriteLine("Generic Container");
Container<ContextBase> myContainerBase = new Container<ContextBase>();
Container<ContextSub> myContainerSub = new Container<ContextSub>();
Console.WriteLine(myContainerBase.GetValue());
Console.WriteLine(myContainerBase.GetOtherValue());
Console.WriteLine(myContainerSub.GetValue());
Console.WriteLine(myContainerSub.GetOtherValue());
Console.ReadKey();
}
}
}
Edit:
I guess my confusion comes from that one can do this
class SomeClass<T> where T: AnotherType, new()
{
T foo = new T();
}
And I expected T to be T even though I understand the compiler would view T as having AnotherType's interface. I assumed the typing of T would happen at run-time even if the interface of T was set at compile time. The T foo declaration seems misleading here because it is really doing
AnotherType foo = new T();
Once I understand that it is not really declaring foo as type T, it is understandable why the new method hiding wouldn't work.
And that's all I have to say about that.
Methods declared new have no relation (from the compiler's perspective) to methods with the same name/signature in the base class. This is simply the compiler's way of allowing you to define different methods in derived classes that share a signature with a method in their base class heirarchy.
Now, with regard to your specific case, realize that generics have to compile to a single set of bytecode regardless of the types that are supplied as generic parameters. As a result, the compiler only knows about the method and properties that are defined on the generic type T - that would be the base type you specify in the generic constraint. The compiler knows nothing about the new methods in your derived type, even if you create an instance of a generic type with the derived type as the parameter. Therefore calls in the generic class will always go to the methods of the base type.
There's a lot of confusion about new/virtual/override; take a look at this SO question - Jason and Eric's answers are excellent. Jon Skeet's answer to a similar question may also help you understand why your implementation behaves the way it does.
There are two possible ways for you to work around this issue:
Perform a conditional cast (based on runtime type information) to the derived type (or an interface) in your generic class. This breaks encapsulation and adds undesirable coupling. It's also fragile if implemented poorly.
Define an interface that you use in your generic constraint that exposes the methods you care about. This may not be possible if the code you are deriving from is not something you can change.
Add another layer - inherit your generic not from your third party class but from a new class which in turn inherits from the third party. In this new class you can define the method in question as new virtual. If all your code never references the third part class directly, it should work
While implementing a design using nested generic collections, I stumbled across those limitations apparently caused by C#'s invariant Generics:
Cannot convert from 'Collection<subtype of T> to 'Collection<T>'
That means, the following will not work, apparently due to the invariance of Generics:
class Outer<TInner, TInnerItem> where TInner : Inner<TInnerItem>
{
public void Add(TInner item)
{
item.Outer = this; // ERROR:
// Cannot implicitly convert from Outer<TInner, TInnerItem>
// to Outer<Inner<TInnerItem>, TInnerItem>
}
}
class Inner<TInnerItem> : ICollection<TInnerItem>
{
Outer<Inner<TInnerItem>, TInnerItem> _outer;
public Outer<Inner<TInnerItem>, TInnerItem> Outer
{
set { _outer = value; }
}
}
(In the actual code, both Inner<> and Outer<> implement ICollection<>.)
I need the Inner<> objects to have a reference to its container collection in order to access some of its data.
How would you implement these nested collections, preferably using a generic approach as outlined above? How would you set the reference to the container collection in the Inner<> class?
Cheers!
Introducing a (possibly abstract) base class which is not dependant on TInner may help you:
abstract class OuterBase<TInnerItem>
{
}
class Outer<TInner, TInnerItem> : OuterBase<TInnerItem> where TInner : Inner<TInnerItem>
{
public void Add(TInner item)
{
item.Outer = this; // Compiles
}
}
class Inner<TInnerItem> : ICollection<TInnerItem>
{
OuterBase<TInnerItem> _outer;
public OuterBase<TInnerItem> Outer
{
set { _outer = value; }
}
}
Or wait for C# 4.0, which introduces co/contra-variant generic interfaces.
The language can't let you convert from Collection<subtype of T> to Collection<T>
Let me explain why.
Imagine you have a Collection<subT> and cast it to Collection<T>. That's ok, since subT inherits from T.
When you retrieve an object from collection_of_T, you're assured that it's ok.
Later, add a T object to collection_of_T. Now you have, in collection_of_subT an object which is not a subT. Whoops.
In order to achieve what you want, you must create a new Collection alltogether.
Collection<T> collection_of_T = new Collection<T>(collection_of_subT);
Which probably is not good for you. Do you really need the TInner generic argument in the Outer class? Would it be possible to replace with Inner<TInnerItem> in the rest of the code instead?