如何将object1 <object2>转换为object1的接口<interface of =“”object2 =“”>?</interface> </object2>

时间:2013-10-07 16:28:39

标签: c# generics interface covariance contravariance

让我说我有这样的安排:

    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以来,它应该没有问题。我的搜索开始引导我进入Covariance和Contravariances,但我在那个级别迷路了。

如何将ICrudService<ICreatable>投射到 public interface ICrudService<out T>

更新

使用协方差:

{{1}}

然后使intellisense说“无效的方差:类型参数'T'必须在'ICrudService.DoSomething(T)'上有效。”T'是协变的。“这是如何工作的?

2 个答案:

答案 0 :(得分:0)

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

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

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

因此,简而言之,这是不可能的。

答案 1 :(得分:0)

您应该将DoSomething更改为接受可强制使用而不是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,此代码将抛出异常。