问题
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