Contra/Covariance 使用泛型 - 无法分配给 T
Contra/Covariance With Generics - Can't Assign to T
代码:
public interface IAssignable
{
IAssignable AssignMe { get; set; }
}
public class GenericAssignExample<T> where T : IAssignable
{
private T _assignable;
public void Valid(T toAssign)
{
_assignable.AssignMe = toAssign;
}
public void AlsoValid(T toAssign)
{
_assignable.AssignMe = toAssign.AssignMe;
}
public void AlsoValidAsWell(T toAssign)
{
_assignable = toAssign;
}
public void Invalid(T toAssign)
{
_assignable = toAssign.AssignMe;
}
}
问题:
在最后一个示例方法 _assignable
(即 T where T is IAssignable
)中,无法为值 toAssign.AssignMe
(属于 IAssignable
类型)赋值,编译器抛出
"Cannot implicitly convert type 'IAssignable' to 'T'".
这是为什么? T
是 IAssignable
那么肯定可以将 IAssignable
的实例分配给它吗?
Why is this? T is IAssignable so surely an instance of IAssignable can be assigned to it?
啊,不是吗? T
是 而不是 IAssignable
,如果是,您就不需要泛型。 T
只是 实施 IAssignable
.
只是因为 Button
和 TextBox
继承自 Control
(或在虚构的示例中实现 IControl
)并不意味着您可以分配 TextBox
到 Button
,反之亦然。
public interface IAssignable
{
IAssignable AssignMe { get; set; }
}
public class A : IAssignable
{
public IAssignable AssignMe { get; set; }
}
public class B : IAssignable
{
public IAssignable AssignMe { get; set; }
}
// You will be able to instantiate this class with either A or B and both must be valid
public class GenericAssignExample<T> where T : IAssignable
{
// here, T refers to either A or B.
private T _assignable;
public void Valid(T toAssign)
{
// assigning either an A or B to the interface...
// always valid, both implement it
_assignable.AssignMe = toAssign;
}
public void AlsoValid(T toAssign)
{
// assigns interface to interface. Always valid.
_assignable.AssignMe = toAssign.AssignMe;
}
public void AlsoValidAsWell(T toAssign)
{
// assigns either an A to an A
// or a B to a B.
// both always valid.
_assignable = toAssign;
}
public void Invalid(T toAssign)
{
// this tries to assign an interface to either an A or a B
// always invalid.
_assignable = toAssign.AssignMe;
}
}
只需将其转换为 IAssingable:
_assignable.AssignMe = (IAssignable)toAssign;
我想我知道你困惑的地方在哪里,注意这里的区别
public interface IAssignable
{
IAssignable AssignMe { get; set; }
}
public class GenericAssignExample
{
private IAssignable _assignable;
public void Valid(IAssignable toAssign)
{
_assignable.AssignMe = toAssign;
}
public void AlsoValid(IAssignable toAssign)
{
_assignable.AssignMe = toAssign.AssignMe;
}
public void AlsoValidAsWell(IAssignable toAssign)
{
_assignable = toAssign;
}
public void Invalid(IAssignable toAssign)
{
_assignable = toAssign.AssignMe;
}
}
现在它应该可以正常工作了。但是请注意,在这里您始终使用接口类型,当您制作带有约束的通用 interface/class 时,您所做的只是缩小可以在 class.[=17= 中使用的类型]
在你的 Invalid
方法中发生的事情是你正在使用一个 IAssignable
对象并将它分配给一个 T
对象,即使 T is IAssignable
有不保证 toAssign.AssignMe
是同一类型,因此您的错误。在我上面所做的修改中,你松散了泛型,然后你使用的实际类型是 IAssignable
所以一切正常。
希望对您有所帮助
代码:
public interface IAssignable
{
IAssignable AssignMe { get; set; }
}
public class GenericAssignExample<T> where T : IAssignable
{
private T _assignable;
public void Valid(T toAssign)
{
_assignable.AssignMe = toAssign;
}
public void AlsoValid(T toAssign)
{
_assignable.AssignMe = toAssign.AssignMe;
}
public void AlsoValidAsWell(T toAssign)
{
_assignable = toAssign;
}
public void Invalid(T toAssign)
{
_assignable = toAssign.AssignMe;
}
}
问题:
在最后一个示例方法 _assignable
(即 T where T is IAssignable
)中,无法为值 toAssign.AssignMe
(属于 IAssignable
类型)赋值,编译器抛出
"Cannot implicitly convert type 'IAssignable' to 'T'".
这是为什么? T
是 IAssignable
那么肯定可以将 IAssignable
的实例分配给它吗?
Why is this? T is IAssignable so surely an instance of IAssignable can be assigned to it?
啊,不是吗? T
是 而不是 IAssignable
,如果是,您就不需要泛型。 T
只是 实施 IAssignable
.
只是因为 Button
和 TextBox
继承自 Control
(或在虚构的示例中实现 IControl
)并不意味着您可以分配 TextBox
到 Button
,反之亦然。
public interface IAssignable
{
IAssignable AssignMe { get; set; }
}
public class A : IAssignable
{
public IAssignable AssignMe { get; set; }
}
public class B : IAssignable
{
public IAssignable AssignMe { get; set; }
}
// You will be able to instantiate this class with either A or B and both must be valid
public class GenericAssignExample<T> where T : IAssignable
{
// here, T refers to either A or B.
private T _assignable;
public void Valid(T toAssign)
{
// assigning either an A or B to the interface...
// always valid, both implement it
_assignable.AssignMe = toAssign;
}
public void AlsoValid(T toAssign)
{
// assigns interface to interface. Always valid.
_assignable.AssignMe = toAssign.AssignMe;
}
public void AlsoValidAsWell(T toAssign)
{
// assigns either an A to an A
// or a B to a B.
// both always valid.
_assignable = toAssign;
}
public void Invalid(T toAssign)
{
// this tries to assign an interface to either an A or a B
// always invalid.
_assignable = toAssign.AssignMe;
}
}
只需将其转换为 IAssingable:
_assignable.AssignMe = (IAssignable)toAssign;
我想我知道你困惑的地方在哪里,注意这里的区别
public interface IAssignable
{
IAssignable AssignMe { get; set; }
}
public class GenericAssignExample
{
private IAssignable _assignable;
public void Valid(IAssignable toAssign)
{
_assignable.AssignMe = toAssign;
}
public void AlsoValid(IAssignable toAssign)
{
_assignable.AssignMe = toAssign.AssignMe;
}
public void AlsoValidAsWell(IAssignable toAssign)
{
_assignable = toAssign;
}
public void Invalid(IAssignable toAssign)
{
_assignable = toAssign.AssignMe;
}
}
现在它应该可以正常工作了。但是请注意,在这里您始终使用接口类型,当您制作带有约束的通用 interface/class 时,您所做的只是缩小可以在 class.[=17= 中使用的类型]
在你的 Invalid
方法中发生的事情是你正在使用一个 IAssignable
对象并将它分配给一个 T
对象,即使 T is IAssignable
有不保证 toAssign.AssignMe
是同一类型,因此您的错误。在我上面所做的修改中,你松散了泛型,然后你使用的实际类型是 IAssignable
所以一切正常。
希望对您有所帮助