interface Base { ... }
class Sub : Base { ... }
class OtherBase<T> where T : Base { ... }
class OtherSub<T> : OtherBase<T> where T : Base { ... }
//...in some class
void Call<T>() where T : OtherBase<Base> { }
//...
Call<OtherSub<Sub>>(); //compile fails...
Seems like when using generics, the compiler won't cast a inner generic type (Base/Sub) in the
generic type (OtherBase/OtherSub). Why does this happen?
Update:
Please also explain the difference between the above and the following (which works)
void Call<T>() where T : Base { }
//...
Call<Sub>();
Forbidding this behaviour (known as “generic variance”) is necessary because otherwise the following code would compile:
List<string> strlist = new List<string>();
List<object> objlist = strlist;
objlist.Add(42);
We’ve added a number to a list of strings. Not good. (Incidentally, the code would compile for arrays instead of Lists because Java allowed this for some reason; however, this will raise a runtime exception.)
You can avoid this in your case though:
static void Call<U, T>(T x) where U : Base where T : OtherBase<U> { }
And call it like this:
Call(new OtherSub<Sub());
C# 4.0 furthermore provides generic variance for interfaces. However, their use isn’t often necessary.
Your issue is linked to a concept called variance/covariance. In fact, if A inherits from B, Class<A> isn't a Class<B>.
See this example:
Class<T> exposes a public method foo(T param)
If Class<A> was a Class<B>, then a method having a reference to Class<B> as a Class<A> and calling foo(B param) (with a B instance) would be calling foo(A param). And B isn't a A.
In fact, Class<A> can inherit from Class<B> only if T is used as a return value only in Class<T>.
This is enforced in .NET 4 through the out keyword for generics interface. Class<T> could therefore implement IClass<out T>.
Konrad has a good advice on how to fix your code. If you wanted to use C# 4's variance, you could do it like this:
interface IOtherBase<out T> where T : Base { }
class OtherBase<T> : IOtherBase<T> where T : Base { }
class OtherSub<T> : OtherBase<T> where T : Base { }
static void Call<T>() where T : IOtherBase<Base> { }
Call<OtherSub<Sub>>() would work then.
Related
I have an interesting situation where I'd like to use a base class utilising a type parameter to implement an interface and also keep things DRY with inheriting classes.
public interface ICalculator
{
void Process(ICalculationModel calculationModel);
}
public abstract class CalculatorBase<T> :ICalculator where T : ICalculationModel
{
// Compiler moans that Process(ICalculationModel calculationModel) isn't implemented
public abstract void Process(T calculationModel);
}
public class PipeworkInspections : CalculatorBase<GasSafetyModel>
{
public override void Process(GasSafetyModel documentModel){
//snip
}
}
Is there something i'm missing with the generic 'where' clause or something? In my head this should work. Or does the compiler need EXACTLY the same implementation as the interface definition?
I can't easily move the type parameter into the ICalculator as there are a lot of places that it is used without any requirement for the generic.
That's cleared things up. Thanks for the info. Now obviously a solution is to make the interface take the type parameter. However ICalculator's are used in a number of places and are referenced just as ICalculator I now get compiler errors if I omit the type parameter in Interfaces that refer to ICalculator... Is there a way to architect this that should work!?
In my head this should work.
The problem then is in your head! :-) This should not work. Let's see why.
interface ICage
{
void Enclose(Animal animal);
}
class ZooCage<T> : ICage where T : Animal
{
public void Enclose(T t) { ... }
}
...
var giraffePaddock = new ZooCage<Giraffe>();
var cage = (ICage)giraffePaddock;
var tiger = new Tiger();
icage.Enclose(tiger);
And now there is a tiger in the giraffe paddock, and life is good for the tiger but bad for the giraffes. That's why this is illegal.
Or does the compiler need EXACTLY the same implementation as the interface definition?
The member which implements an interface member must exactly match the signature of the implemented method. For example, you cannot use return type covariance:
interface I
{
Animal GetAnimal();
}
class C : I
{
public Giraffe GetAnimal() { ... } // not legal.
}
The contract requires an animal; you provide a giraffe. That should work, logically, but this is not legal in C#. (It is in C++.)
See any of the many questions on this site about return type covariance for the reasons why.
Similarly for parameter type contravariance:
interface I
{
void PutMammal (Mammal mammal);
}
class C : I
{
public PutMammal(Animal animal) { ... } // not legal.
}
Again, this is logically sensible; the contract requires that you take a mammal, and this takes any animal. But again, this is not legal.
There are some covariant and contravariant operations in C#; see any of numerous questions on those topics on this site, or browse the covariance and contravariance articles on ericlippert.com or my previous msdn blog.
If this worked then you'd be able to say something like this:
PipeworkInspections pipeworks = new PipeworkInspections();
ICalculator calculator = pipeworks;
NuclearPowerSafetyModel nuclearModel = new NuclearPowerSafetyModel();
calculator.Process(nuclearModel); // <-- Oops!
That's probably not what you wanted...
Your interface says any class implementing it will provide this method:
void Process(ICalculationModel calculationModel);
Now obviously PipeworkInspections does not. It does not have a method Process that accepts any ICalculationModel. IT only has a method accepting specific implementations of ICalculationModel. So your compilation fails.
Yes, you need the exact implementation.
As an alternative you can make interface and Process method generic if it works for you:
public interface ICalculator<T> where T : ICalculationModel
{
void Process(T calculationModel);
}
public abstract class CalculatorBase<T> : ICalculator where T : ICalculationModel
{
public abstract void Process(T calculationModel);
}
I agree with Eric Lippert's response: you can't. And he explained in a very good way why this happens.
If you really want to do this, you can add the following to your abstract class, and it will compile:
void ICalculator.Process(ICalculationModel calcMod)
{
Process((T)calcMod);
}
But you need to know what you are doing, otherwise you might have some InvalidCastException at runtime.
I'm having a hard time understanding why it would be beneficial to do something like this: (Sample is a class)
static void PrintResults<T>(T result) where T : Sample
Wouldn't it be better to to just pass Sample into the method?
static void PrintResults (Sample result)
I recommend avoiding generic types where non-generic syntax works, such as the example you gave. However, there are other useful cases.
For example, specifying the return type generically:
static T Create<T>() where T: Sample, new()
{
return new T();
}
// Calling code
Sample sample = Create<Sample>();
instead of
static object Create()
{
return new Sample();
}
// Calling code
Sample sample = (Sample) Create();
You can also use templates to place multiple restrictions on a type. For example:
static T Create<T>() where T: IMyInterface, new()
{
return new T();
}
interface IMyInterface {}
class MyClass : IMyInterface { }
// Calling code.
MyClass myClass = Create<MyClass>();
This allows the generic creation of a new type that implements a specific interface and has a generic constructor. Also:
static void DoSomething<T>(T t) where T: IMyInterface1, IMyInterface2
{
t.MethodOnIMyInterface1();
t.MethodOnIMyInterface2();
}
interface IMyInterface1
{
void MethodOnIMyInterface1();
}
interface IMyInterface2
{
void MethodOnIMyInterface2();
}
class MyClass: IMyInterface1, IMyInterface2
{
// Method implementations omitted for clarity
}
// Calling code
MyClass myclass'
DoSomething(myclass); // Note that the compiler infers the type of T.
Where you can require multiple interfaces on a single parameter without (1) creating a new type that implements all these interfaces and (2) requiring parameters to be of that type.
As #dcastro points out in his/her answer, generic types can also tell the compiler to require types are the same. For example:
static void DoSomething<T>(T t1, T t2) where T: MyType
{
// ...
}
class MyType {}
class MyType1: MyType {}
class MyType2: MyType {}
// Calling code
MyType1 myType1;
MyType2 myType2;
DoSomething<MyType>(myType1, myType2);
Where the compiler requires that t1 and t2 are the same type but can be any type that inherits MyType. This is useful in automated unit testing frameworks, such as NUnit or MSTest, for generic equality and comparison checks.
Most of the answers are offering explanations of the usefulness of generics involving interfaces that don't really seem to address your actual question.
Truth is, for the example you posted, there is no benefit to using a generic method. It is actually worse because it will cause multiple implementations of the same function to be generated and ever slightly increase the code size at runtime.
In voids you could allways use an interface as a parameter to make multiple types work, so generics arent often useful here.
Only exceptions are the constraints on generics. And by that i dont mean something like
where T: IA, IB
since this could be done by an interface aswell that both implements IA and IB. This will get tiresome at some point however since you will need more and more interfaces. So lets look ath the "special constraints" class and new
public void AddNew(List<T> items) where T : new
{
items.Add(new T());
}
and class which is useful if the method mutates its parameter, which wont work for structs
static void IncA<T>(T item) where T: class, IA
{
item.A++;
}
The real power of generics is when methods have a generic return type or generic classes like List <T>. You dont want to implement a new class for every List you will need.
My current non-compiling code is similar to this:
public abstract class A { }
public class B { }
public class C : A { }
public interface IFoo<T>
{
void Handle(T item);
}
public class MyFoo<TA> : IFoo<TA>, IFoo<B>
where TA : A
{
public void Handle(TA a) { }
public void Handle(B b) { }
}
The C# compiler refuses to compile this, citing the following rule/error:
'MyProject.MyFoo<TA>' cannot implement both 'MyProject.IFoo<TA>' and 'MyProject.IFoo<MyProject.B>' because they may unify for some type parameter substitutions
I understand what this error means; if TA could be anything at all then it could technically also be a B which would introduce ambiguity over the two different Handle implementations.
But TA can't be anything. Based on the type hierarchy, TA can't be a B - at least, I don't think it can. TA must derive from A, which does not derive from B, and obviously there's no multiple class inheritance in C#/.NET.
If I remove the generic parameter and replace TA with C, or even A, it compiles.
So why do I get this error? Is it a bug in or general un-intelligence of the compiler, or is there something else I'm missing?
Is there any workaround or am I just going to have to re-implement the MyFoo generic class as a separate non-generic class for every single possible TA derived type?
This is a consequence of section 13.4.2 of the C# 4 specification, which states:
If any possible constructed type created from C would, after type arguments are substituted into L, cause two interfaces in L to be identical, then the declaration of C is invalid. Constraint declarations are not considered when determining all possible constructed types.
Note that second sentence there.
It is therefore not a bug in the compiler; the compiler is correct. One might argue that it is a flaw in the language specification.
Generally speaking, constraints are ignored in almost every situation in which a fact must be deduced about a generic type. Constraints are mostly used to determine the effective base class of a generic type parameter, and little else.
Unfortunately, that sometimes leads to situations where the language is unnecessarily strict, as you have discovered.
It is in general a bad code smell to implement "the same" interface twice, in some way distinguished only by generic type arguments. It is bizarre, for example, to have class C : IEnumerable<Turtle>, IEnumerable<Giraffe> -- what is C that it is both a sequence of turtles, and a sequence of giraffes, at the same time? Can you describe the actual thing you're trying to do here? There might be a better pattern to solve the real problem.
If in fact your interface is exactly as you describe:
interface IFoo<T>
{
void Handle(T t);
}
Then multiple inheritance of the interface presents another problem. You might reasonably decide to make this interface contravariant:
interface IFoo<in T>
{
void Handle(T t);
}
Now suppose you have
interface IABC {}
interface IDEF {}
interface IABCDEF : IABC, IDEF {}
And
class Danger : IFoo<IABC>, IFoo<IDEF>
{
void IFoo<IABC>.Handle(IABC x) {}
void IFoo<IDEF>.Handle(IDEF x) {}
}
And now things get really crazy...
IFoo<IABCDEF> crazy = new Danger();
crazy.Handle(null);
Which implementation of Handle gets called???
See this article and the comments for more thoughts on this issue:
http://blogs.msdn.com/b/ericlippert/archive/2007/11/09/covariance-and-contravariance-in-c-part-ten-dealing-with-ambiguity.aspx
Apparently it was by design as discussed at Microsoft Connect:
Allow to implement same generic interface for more that one type parameter in generic class under some conditions
And the workaround is, define another interface as:
public interface IIFoo<T> : IFoo<T>
{
}
Then implement this instead as:
public class MyFoo<TA> : IIFoo<TA>, IFoo<B>
where TA : A
{
public void Handle(TA a) { }
public void Handle(B b) { }
}
It now compiles fine, by mono.
You can sneak it under the radar if you put one interface on a base class.
public interface IFoo<T>
{
}
public class Foo<T> : IFoo<T>
{
}
public class Foo<T1, T2> : Foo<T1>, IFoo<T2>
{
}
I suspect this works because if the types do "unify" it is clear the derived class's implementation wins.
See my reply to basically the same question here:
https://stackoverflow.com/a/12361409/471129
To some extent, this can be done! I use a differentiating method, instead of qualifier(s) limiting the types.
It does not unify, in fact it might be better than if it did because you can tease the separate interfaces apart.
See my post here, with a fully working example in another context.
https://stackoverflow.com/a/12361409/471129
Basically, what you do is add another type parameter to IIndexer, so that it become IIndexer <TKey, TValue, TDifferentiator>.
Then you when you use it twice, you pass "First" to the 1st use, and "Second" for the 2nd use
So, class Test becomes: class Test<TKey, TValue> : IIndexer<TKey, TValue, First>, IIndexer<TValue, TKey, Second>
Thus, you can do new Test<int,int>()
where First, and Second are trivial:
interface First { }
interface Second { }
Taking a guess now...
Couldn't A, B and C be declared in outside assemblies, where the type hierarchy may change after the compilation of MyFoo<T>, bringing havoc into the world?
The easy workaround is just to implement Handle(A) instead of Handle(TA) (and use IFoo<A> instead of IFoo<TA>). You cant do much more with Handle(TA) than access methods from A (due to the A : TA constraint) anyway.
public class MyFoo : IFoo<A>, IFoo<B> {
public void Handle(A a) { }
public void Handle(B b) { }
}
Hmm, what about this:
public class MyFoo<TA> : IFoo<TA>, IFoo<B>
where TA : A
{
void IFoo<TA>.Handle(TA a) { }
void IFoo<B>.Handle(B b) { }
}
I know it has been a while since the thread was posted but for those who come down to this thread via the search engine for help. Note that 'Base' stands for base class for TA and B in below.
public class MyFoo<TA> : IFoo<Base> where TA : Base where B : Base
{
public void Handle(Base obj)
{
if(obj is TA) { // TA specific codes or calls }
else if(obj is B) { // B specific codes or calls }
}
}
Could somebody kindly explain this to me, in simple words:
there is no way to constrain a type to
have a static method. You cannot, for
example, specify static methods on an
interface.
many thanks in advance to you lovely people :)
With generics, you can add a constraint that means the generic-type supplied must meet a few conditions, for example:
where T : new() - T must have a public parameterless constructor (or be a struct)
where T : class - T must be a reference-type (class / interface / delegate)
where T : struct - T must be a value-type (other than Nullable<TSomethingElse>)
where T : SomeBaseType - T must be inherited from SomeBaseType (or SomeBaseType itself)
where T : ISomeInterface - T must implement ISomeInterface
for example:
public void SomeGenericMethod<T>(T data) where T : IEnumerable {
foreach(var obj in data) {
....
}
}
it is SomeBaseType and ISomeInterface that are interesting here, as they allow you to demand (and use) functions defined on those types - for example, where T : IList gives you access to Add(...) etc. HOWEVER! simply: there is no such mechanism for things like:
constructors with parameters
static methods
operators / conversions
arbitrary methods not defined via a base-type or interface
so: you can't demand those, and you can't use them (except via reflection). For some of those dynamic can be used, though.
so, basically:
public class A{}
public class B{
public static void Foo() {}
}
You can't write a generic constraint for T in:
public class C<T> {}
Such that you restrict to accept only A or B based on the presence or non-presence of the static method Foo().
Imagine the following not working code:
interface IWithStatic
{
void DoIt(); // non-static
static void DoItStatic(); // static
}
class C1 : IWithStatic
{
void DoIt() {} // non-static
static void DoItStatic(){} // static
}
class C2 : IWithStatic
{
void DoIt() {} // non-static
static void DoItStatic(){} // static
}
And, in a program :
IWithStatic myObj = GetWithAnyMethod(); // Return a C1 or C2 instance
myObj.DoIt(); // working, as the runtime type is used (either C1 or C2);
but with the static... how can the compiler interpret this :
IWithStatic.DoItStatic(); // Not knowing which type to use
Do you see what's the problem now ?
It is not possible to have:
public interface IInterface {
static void Method();
}
This is because you are not allowed/able to constrain implementing classes to methods being static.
In the below code "where T : WsgTypes.RouteRestriction", can I add multiple classes so that T can be of only those few classes types which I am interested of
public static T GetDetails<T>(string code) where T : WsgTypes.RouteRestriction
{
T details;
if (typeof(T) == typeof(WsgTypes.TicketType))
{
details = TicketTypeDetail.GetDetails(code) as T;
}
else if (typeof(T) == typeof(WsgTypes.RouteRestriction))
{
details = RouteRestrictionDetail.GetDetails(code) as T;
}
else
{
throw new NotSupportedException("");
}
return details;
throw new NotImplementedException();
}
It seems to me that this isn't a proper use of generics. It would be better if TicketType and RouteRestriction implemented some IDetailed.
No, generic type constraints can only specify a single base-class.
You can specify multiple interfaces, but this is "all of", not "any of".
What you ask is possible with overloading, but not with generics.
For inheritance you can have a single class with multiple interfaces.
public static T GetDetails<T>(string code) where T : WsgTypes.RouteRestriction, , IComparable
{
}
Instead you can have an interface and have multiple classes implementing it.
public interface IInterface
{}
public class Class1: IInterface
{}
public class Class2: IInterface
{}
public static T GetDetails<T>(string code) where T:IInterface
{
T instance;
// ...
return instance;
}
I'm afraid you can't. The usual way is to provide a common interface that all classes you're interested in implement. The problem is that, inside the generic body, the compiler expects a generic type parameter to be unambigous.
Well, or you could take an object as parameter and cast it at your will. But... no. Don't.
Note that instead of typeof, you could also use the is and as operators.
See this article...
http://msdn.microsoft.com/en-us/library/d5x73970.aspx
... for more information on constaints. You can add multiple constraints, and you can constrain by some interface or by some base class, but not by a list of arbitrary classes.
Here's an example of multiple constraints (from the above):
class Base { }
class Test<T, U>
where U : struct
where T : Base, new() { }
Did you try separating them like this:
public static T GetDetails<T>(string code) where T : WsgTypes.RouteRestriction, NextClass, AnotherClass, AndSoOn
{
...
}