1

假设我有这样的安排:

    public interface ICreatable
    {
        int CreatedByUserId { get; set; }
    }

    public class Unicorn : ICreatable
    {
        public int CreatedByUserId { get; set; }
    }

    public interface ICrudService<T>
        where T : class, ICreatable
    {
        T DoSomething(T t);
    }

    public class UnicornService : ICrudService<Unicorn>
    {
        public Unicorn DoSomething(Unicorn unicorn)
        {
            var createdByUserId = unicorn.CreatedByUserId;

            // ...

            return unicorn;
        }
    }

并像这样使用它:

    static void Main(string[] args)
    {
        var unicorn = new Unicorn();
        var unicornService = new UnicornService();

        unicornService.DoSomething(unicorn);
    }

这运行良好。但是,假设我想将unicornService它的接口类型及其ICrudService泛型类型转换为它的接口类型,如下所示:

        var crudService = unicornService as ICrudService<ICreatable>;

我遇到了问题。这是它的外观:

unicornService as ICrudService<Unicorn> --> casts is fine
unicornService as ICrudService<ICreatable> --> casts to null

似乎因为Unicorn源自ICreatable并且因为ICrudService<T> where T: class, ICreatable它应该没有问题解决这个问题。我的搜索开始引导我进入协变和逆变,但我在那个级别迷路了。

我怎样才能crudService投到ICrudService<ICreatable>

更新:

像这样使用协方差:

    public interface ICrudService<out T>

然后让智能感知说“无效的方差:类型参数 'T' 必须在 'ICrudService.DoSomething(T)' 上逆变有效。'T' 是协变的。” 这是如何运作的?

4

2 回答 2

0

您应该更改 DoSomething 以接受ICreatable而不是 T 以使用out T修饰符:

public interface ICrudService<out T>
    where T : class, ICreatable
{
    T DoSomething(ICreatable t);
}

public class UnicornService : ICrudService<Unicorn>
{
    public Unicorn DoSomething(ICreatable t)
    {
        var unicorn = (Unicorn)t;
        var createdByUserId = unicorn.CreatedByUserId; // or t.CreatedByUserId

        // ...

        return unicorn;
    }
}

请注意,如果将非 Unicorn 传递给 UnicornService,此代码将引发异常。

于 2013-10-07T16:59:09.030 回答
0

AnICrudService<Unicorn>不能被视为ICrudService<ICreatable>

一个ICrudService<Unicorn>对象只允许接受 的类型Unicorn或子类型的参数Unicorn,但ICrudService<ICreatable>可以接受 的参数SomeOtherTypeOfICreatable

允许您UnicornService键入特定于 的成员Unicorn,而不仅仅是ICreatable,因为这是它限制其功能的类型。该限制禁止它满足更通用接口的 API。

所以,简而言之,这是不可能的。

于 2013-10-07T16:51:03.797 回答