问题
public interface ILovable<T> where T : IEquatable<T>
{
T Care(T t);
}
public class Me : ILovable<int>
{
public int Care(int i)
{
return i;
}
}
Say I have the above. Now below function fails:
private static void Colour<T>(ILovable<T> me) where T : IEquatable<T>
{
var z = me.Care(1); //cannot convert from 'int' to 'T'
}
What's failing the above piece of code? ILovable<T> has a Care function which intakes a T which is IEquatable<T>. In the above function I'm calling the same Care function and passing T which is int type. int is after all IEquatable<int>.
What am I doing wrong? Is there any work around to get it fixed?
回答1:
Your method signature does not specify a ILovable<int>, it specifies an ILovable<T>. This, for example, would work:
private static void Colour(ILovable<int> me)
{
var z = me.Care(1); //cannot convert from 'int' to 'T'
}
The problem is the compiler doesn't know that T is an 'int' in your example; it could be any type that meets the constraint. Here is another way that would work:
private static void Colour<T>(ILovable<T> me, T valueToCareAbout) where T : IEquatable<T>
{
var z = me.Care(valueToCareAbout);
}
//use like this
Colour(me, 1);
回答2:
The error I get is:
Argument type 'int' is not assignable to parameter type 'T'
I'm pretty sure this is because you are defining me as an ILovable<T>. Therefore, it doesn't automatically resolve to the Me type where int is defined as T.
This will fix the error because Me defines T as an int:
private static void Colour<T>(Me me) where T : IEquatable<T>
{
var z = me.Care(1);
}
回答3:
Well that's because method Colour says that there will be parameter of type ILovable< T > whereas T would be resolved later, so at compile time either I tell method that T is int type.
So either you pass ILovable as parameter and grantee that T is int
void Colour<T>(ILovable<int> me)
or pass type Me directly
void Colour<T>(Me me)
Because otherwise me.Care is expecting type T not int as specific
回答4:
Change following
private static void Colour<T>(ILovable<T> me) where T : IEquatable<T>
To
private static void Colour<Int32>(ILovable<int> me)
and above will work.
Now the mystry portion
You are getting error in following
private static void Colour<T>(ILovable<T> me) where T : IEquatable<T>
because Care is expecting T, and you are providing int.
It is same as
Care((T)1).
or
T t = (T)1; //This is the cause of error as int cannot be changed to T. Remember Int32 is sealed so T cannot derive from int
Care(t); // This is fine
To make above work, T has to int. To make it so, Colur method syntax should be like
private static void Colour<Int32>(ILovable<int> me)
If you want to pass string to Care, T should be string.
private static void Colour<string>(ILovable<string> me)
{
me.Care("Hello");
}
Now if we have to fix T then question arises why T is required at all in Colour definition.
Answer -> For non taking care of inheritance type in non sealed class.
回答5:
The short answer is overriding variable of type T inside a generic method (or class) with a more derived type is not possible since compiler doesn't explicitly know T is that more derived type (in our case T is int), because T can be any other more derived type at run time.
Long answer: me variable is of type ILovable<T>. Now me.Care function is expecting parameter of type that is specified on ILovable<T> which is T. Outside the Care function T can be anything that is IEquatable<T>, so int is ok. But inside the function, T has to be just T and not another derived type of IEquatable<T>. Otherwise there will be runtime error for scenarios like this:
private static void Colour<T>(ILovable<T> me) where T : IEquatable<T>
{
var z = me.Care(1);
}
...
Colour("");
Right now, T is string when calling Colour(""). So me is ILovable<string>. So me.Care function expects a string as parameter but provided is an int and that is disaster.
来源:https://stackoverflow.com/questions/14082431/cannot-pass-variable-of-type-conforming-to-generic-constraint