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'".

这是为什么? TIAssignable 那么肯定可以将 IAssignable 的实例分配给它吗?

Why is this? T is IAssignable so surely an instance of IAssignable can be assigned to it?

啊,不是吗? T 而不是 IAssignable,如果是,您就不需要泛型。 T 只是 实施 IAssignable.

只是因为 ButtonTextBox 继承自 Control(或在虚构的示例中实现 IControl)并不意味着您可以分配 TextBoxButton,反之亦然。


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 所以一切正常。

希望对您有所帮助