I want a generic class to implement the IEquatable<T> interface. The class has data items of type T. For the generic class to be equatable the data items need to be that as well.
Here is my generic class:
public class V<T> : IEquatable<V<T>> where T : IEquatable<T>
{
public V(T[] Value)
{
this.Value = Value;
}
T[] Value { get; set; }
public bool Equals(V<T> other)
{
if (Value.Count() != other.Value.Count()) return false;
for (int i = 0; (i < Value.Count()) && i < other.Value.Count(); i++)
{
if (!Value[i].Equals(other.Value[i])) return false;
}
return true;
}
}
And here is the problem.
When I compile the above generic class I get the following message.
GenericArguments[0], 'T' on 'Myspace.Generic.V`1[T]' violates the constraint of type parameter 'T'.
Where do I make the mistake in my reasoning or what is wrong with my generic class?
Note:
When I leave IEquatable<V<T>> out at the generic class and the code for public bool Equals(V<T> other) intact then the generic class compiles and is usable. Except for detecting IEquitable by the compiler.
public class V<T> where T : IEquatable<T>
{
The above code works but instances of V<T> are no longer recognised as IEquitable
Note2:
Thanks to dasblinkenlight for trying this code in a solution on its own I found out that it is most likely a configuration problem and not a coding problem. I now consider this specific question as answered but I've not yet identified my configuration problem.
Note3:
The actual cause of the problem is an NUnit test module that loads the dll through an accessor. Changing the test procedures is required but IEquatable<V<T>> is now used wihtout any problems.
Problem Solved.
There is nothing wrong with your generic class. Something is wrong with the class that you are passing as its generic parameter T. Namely, SomeClass, the class that you pass in V<SomeClass> does not implement IEquitable<SomeClass>.
Your V<T> class requires T to be an implementation of IEquitable<T>. You need it in order to check element-by-element equality of arrays using the Value[i].Equals(other.Value[i]) expression. If whatever class that you use as V<T>'s generic parameter is not equitable to itself, the compiler would complain.
Related
The most common example I have found to explain why contravariantly-valid type parameters cannot be used covariantly has involved constructing some read-write wrapper of a derived type, casting it to a wrapper of the base type, injecting a different derived type, then later reading that wrapped value; something along the lines of the following:
class Base { public int base_property; }
class Derived : Base { public int derived_property; }
class OtherDerived : Base { public string other_derived_property; }
interface Wrapper<out T> {
void put(T v);
T pull();
}
Wrapper<Derived> derived_wrapper = new WrapperImpl<Derived>();
Wrapper<Base> cast_wrapper = (Wrapper<Base>)derived_wrapper;
cast_wrapper.put(new OtherDerived());
Derived wrapped = derived_wrapper.pull(); // Surprise! This is an OtherDerived.
I can understand why this is invalid. But what if Wrapper didn't have pull, and the property it wraps has a private getter? The problem with the (Wrapper<Base>)derived_wrapper cast seems to disappear, and I can't find a problem to replace it.
More specifically, I'm not aware of any way for functionality to be conditional on the eventual concrete type of a generic. Unsurprisingly, asserting the type like the following is no use:
class WrapperImpl<T> : Wrapper<T> where T : Base {
public void put(T v) {
if(typeof(T).Equals(Derived)) {
Console.WriteLine(v.derived_property); // Type `T' does not contain a
// definition for `derived_property'...
}
}
}
This leads me to believe that functionality in these methods can only make use of properties of the type T is constrained to. Even if the wrapped property is an OtherDerived where the original WrapperImpl expected a Derived (before being cast), no method could expect that wrapped property to have derived_property because Base is the most specific T is guaranteed to be.
Am I missing something here, or perhaps is this a limitation of the compiler to not be able to concretize T on the fly?
(I'm guessing that a class like Wrapper finds few uses, but the rules of variance appear quite broad and sweeping, and I'm curious if there are finer rules in play.)
The T in WrapperImpl<T> can be constrained on any subtype of Base, not just Base itself. Functionality in put should be able to safely access v.derived_property if T : Base is simply changed to a T : Derived.
This is the source of trouble when an OtherDerived is passed to put after the (Wrapper<Base>)derived_wrapper cast, in trying to access the nonexistent derived_property.
I have a good understanding of OOP in general, inheritance and polymorphism, interfaces, etc. I encountered a strange situation and I don't understand why it does not work at all...
EDIT : Ok, I found out that covariance (or contravariance?) may solve this problem, but crucially
we're still using .NET 2.0
How can I solve this without moving to C# 4.0 ?
Here is the situation. Given these two classes :
public class CustomCollectionType<T> : IEnumerable<T>
{
/* Implementation here, not really important */
}
public class Entity : EntityBase
{
/* Implentation here, not important */
}
The compiler complains when I try to have this generic method
public void LoopThrough(IEnumerable<EntityBase> entityList)
{
foreach(EntityBase entity in entityList)
{
DoSomething(entity);
}
}
And try to use it this way :
CustomCollectionType<Entity> entityList;
/* Add items to list */
LoopThrough(entityList);
Error says I cannot convert from CustomCollectionType<Entity> to IEnumerable<EntityBase>.
However, I can do this :
public void Foo(EntityBase entity)
{
entity.DoSomething();
}
Foo(new Entity());
And this :
public void Bar(IEnumerable<Entity> entityList)
{ ... }
CustomCollectionType<Entity> entityList;
Bar(entityList);
Why can't I create my method with the highest classes in the hierarchy? The types are obviously compatible... Am I missing something ?
EDIT : I want to solve this problem without altering the existing classes in any way, so creating a new method in any of the classes, or implementing an additional interface is out of the question.
Let's consider your first case. You have:
class Bowl<T> : IEnumerable<T> {}
class Apple : Fruit {}
...
void LoopThrough(IEnumerable<Fruit> fruits) ...
and you call
Bowl<Apple> apples = whatever;
LoopThrough(apples);
This fails in C# 3.0; it succeeds in C# 4.0 because IEnumerable<T> is now covariant in T; a sequence of apples can be used as a sequence of fruits.
To make it work in C# 3.0 you can use the Cast sequence operator.
Bowl<Apple> apples = whatever;
LoopThrough(apples.Cast<Fruit>());
To make it work in C# 2.0, implement the Cast sequence operator yourself. It is only a couple lines of code.
Note that in C# 4.0 it will still not be legal to say:
Bowl<Fruit> fruits = new Bowl<Apples>();
because of course you can say:
fruits.Add(new Orange());
and you just put an orange into a bowl that can only contain apples.
Yes, .NET can be kind of annoying that way as it can't cast all of your generic parameters in one shot. Instead, perhaps try a generic approach like this to alleviate the problem.
public void LoopThrough<T>(IEnumerable<T> entityList) where T : EntityBase
{
foreach(T entity in entityList)
{
DoSomething(entity as EntityBase);
}
}
The types are compatible but sort of uncompatible, the major reason here is that you are using the base type in parameter as IEnumerable and not the actual type although Entity's base is entitybase because the rules for type parameters and constraints have several implications for generic class behavior, especially regarding inheritance and member accessibility
Generic classes are invariant. In other words, if an input parameter specifies a List<BaseClass>, you will get a compile-time error if you try to provide a List<DerivedClass>.
And thats why you get that error where as in your last e.g. the T is same.
However it would have worked absolutely fine had you used interfaces because all interfaces are compatible
public class Entity : IEntityBase
{ /* Implentation here, not important */ }
public void LoopThrough(IEnumerable<IEntityBase> entityList)
{ foreach(IEntityBase entity in entityList)
{ DoSomething(entity); } }
and than your method will work fine
CustomCollectionType<Entity> entityList; LoopThrough(entityList);
because entitylist has a type of IEntityBase
The other thing you can try is typeof(to get type) or using a cast and it should work
I might be missing something, but if your intent of CustomCollectionType is supposed to be of an Entity base yet allowed to use the IEnumerable, shouldn't you have IT as a base of Entity base first? such as...
public class CustomCollectionType<T> : EntityBase, IEnumerable<T>
{
/* Implementation here, not really important */
}
Then your LoopThrough SHOULD work as the custom collection type is derived FROM the EntityBase and have whatever expected methods, properties, etc available... or worst case, you would type-cast it when calling the function such as
Bowl<Apple> apples = whatever;
LoopThrough((EntityBase)apples);
Perhaps this is a simple newbie C# question, but so be it---it will be a fresh break from my other questions, which are so difficult that no one knows the answer to them. :)
Let's say I have a generic type in C#:
Thing<T>
And let's say I want to make a thing using a static factory method. In Java, this is no problem:
public static <T> Thing<T> createThing()
{
return flag ? new Thing<Integer>(5) : new Thing<String>("hello");
}
How do I do this in C#? Thanks.
If you want to return an instance of a templated class using one of many different template arguments, one way to do it is with an abstract base (or an interface):
abstract class UntypedThing { }
class Thing<T> : UntypedThing
{
public Thing(T t) { }
}
class Foo
{
public static UntypedThing createThing(bool flag)
{
if (flag)
return new Thing<int>(5);
else return new Thing<String>("hello");
}
}
The UntypedThing class would contain as much code as possible that does not rely on the template type. The Thing class would ideally only contain code that relies on the template type. The factory class Foo always returns the former.
You can in theory use reflection to build up the correct generic type, but it will be pretty useless to you as at some point you will need to upcast it to a less specific type.
public class ThingFactory {
public object Create(bool flag) {
Type outputType = null;
if(flag) {
outputType = typeof(string);
} else {
outputType = typeof(int);
}
return Activator.CreateInstance(typeof(Thing<>).MakeGenericType(outputType));
}
}
As you can see, the value of doing this is about zero as you will need to cast the return type to the type you want, meaning that the logic to determine it needs to live outside the Create method.
I would use Reinderien's method and have a non-generic base. This is the most sane and idiomatic approach.
Oh, the trouble I get myself in when I simply try to do something simple.
It turns out that C# 4 allows this sort of covariance---sort of. First, I have to make Thing an interface and specify the "out" generic parameter:
public interface Thing<out T> {...}
But if I do certain things, C# won't let me use covariance. For example, if I try to return T from the interface:
public interface Thing<out T>
{
public T GetT();
Even if I manage to get covariance with Thing, what do I do with it?
Thing<object> thing=createThing();
The compiler tells me that the type cannot be inferred from usage.
Let's say I say screw the whole T thing and make the factory method return Thing of type object:
public static Thing<object> createThing() {...}
Fine, but now where do I put it?
IList<Thing<object>> list=new List<Thing<object>>();
Thing<object> thing=createThing();
list.Add(thing);
Yes, I have to say that this is a list of Thing with T of type Object, because C# has no wildcard type.
If this were Java, I'd simply say:
public class Thing<T> {...}
public static <T> Thing<T> createThing() {...}
List<?> things=new ArrayList<Thing<?>>();
Thing<?> thing=createThing();
things.add(thing);
If I wanted extra safety by saying that T had to be of a special type, I'd say:
public static <T extends MyBaseType> Thing<T> createThing() {...}
List<? extends MyBaseType> things=new ArrayList<Thing<? extends MyBaseType>>();
Thing<? extends MyBaseType> thing=createThing();
things.add(thing);
Then I'd figure out what T is later, when I had more information.
This all seems to come down to incomplete generic covariance in C# coupled with the lack of C# generic wildcards. (I still maintain it isn't an erasure issue.)
So what do I do? The only simple thing to do seems to follow Reinderien's answer and split out a non-generic base class.
(I wonder if in this non-generic base class I could have object getValue() and then use covariance in the subclass to return T getValue()? Ack, I'm tired of this---I'll leave that for another day.)
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