对齐/协方差与泛型 - 无法分配给T.

时间:2017-05-15 11:47:35

标签: c# generics covariance contravariance

代码:

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;
    }
}

问题:

在最后一个示例中,方法_assignableT where T is IAssignable)无法赋值toAssign.AssignMe(类型为IAssignable),编译器抛出

  

“无法将类型'IAssignable'隐式转换为'T'”。

这是为什么? TIAssignable,所以肯定可以为IAssignable分配一个实例吗?

3 个答案:

答案 0 :(得分:1)

  

这是为什么? T是IAssignable所以肯定可以为它分配一个IAssignable实例吗?

啊,不是吗? T IAssignable,如果是,则不需要Generics。 T只是实现 IAssignable

仅仅因为ButtonTextBox继承自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;
    }
}

答案 1 :(得分:0)

将它投射到IAssingable:

_assignable.AssignMe = (IAssignable)toAssign;

答案 2 :(得分:0)

我认为我知道你感到困惑的地方,请注意差异

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;
    }
}

现在它应该按照你的意图工作。但请注意,在这里,您始终使用接口类型,当您创建带有约束的通用接口/类时,您所做的只是缩小可以在您的类中使用的类型。

在您的Invalid方法中,您发现的是使用IAssignable对象并将其分配给T对象,即使T is IAssignable没有保修toAssign.AssignMe是同一类型,因此您的错误。在我上面做的修改中,你松散了泛型,然后你使用的实际类型是IAssignable,所以一切正常。

希望有所帮助