如何将类型转换为以另一个接口作为通用参数的通用接口

时间:2019-01-15 21:31:09

标签: c# generics interface polymorphism parametric-polymorphism

我正在尝试从代码中删除多余的if-else逻辑,并且仍然 根据用户的选择执行适当的方法。

我在main方法中遇到编译器错误。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp5
{
    public interface IBaseService<TVM> where TVM : IBaseVM
    {
        TVM Method1();
        void Method2(TVM param);
    }

    public interface IBaseVM
    {
        int Id { get; set; }
        string Name { get; set; }
    }

    public class Child1VM : IBaseVM
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Child2VM : IBaseVM
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Child1Service : IBaseService<Child1VM>
    {
        public Child1VM Method1() { return new Child1VM(); }
        public void Method2(Child1VM param)
        {
            return; //body... }
        }
    }

    public class Child2Service : IBaseService<Child2VM>
    {
        public Child2VM Method1() { return new Child2VM(); }
        public void Method2(Child2VM param)
        {
            return; //body... }
        }
    }

    public class Driver
    {
        public static void Main(string[] ars)
        {
            IBaseService<Child1VM> child1Service = new Child1Service(); // why cant this be of IBaseVM type ?
            IBaseService<Child2VM> child2Service = new Child2Service(); // why cant this be of IBaseVM type ?

            IBaseService<IBaseVM>[] services = new IBaseService<IBaseVM>[]
                {
                    child1Service,   // error
                    child2Service    // error
                };
        }
    }

}

我希望能够调用子服务,而不必使用if-else /切换大小写逻辑。

如果所有子类都可以存储在上述数组中,那么我可以根据用户的选择简单地调用相应子类的适当方法(使用数组索引)。

1 个答案:

答案 0 :(得分:0)

除非将Child1Service中的IBaseService<Child1VM>定义为协变量,否则无法将T投射到IBaseService<T>IBaseService<out T>

现在它将给您这个错误:

  

CS1961无效方差:类型参数“ TVM”在“ IBaseService.Method2(TVM)”上必须相反有效。 “ TVM”是协变的。

因此,您必须将Method2的参数从Child1VM更改为IBaseVM

这将起作用:

public interface IBaseService<out TVM> where TVM : IBaseVM
{
    TVM Method1();
    void Method2(IBaseVM param);
}

public interface IBaseVM
{
    int Id { get; set; }
    string Name { get; set; }
}

public class Child1VM : IBaseVM
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Child1Service : IBaseService<Child1VM>
{
    public Child1VM Method1() { return new Child1VM(); }
    public void Method2(IBaseVM param)
    {
        return; //body... }
    }
}

public class Driver
{
    public static void Main(string[] ars)
    {
        IBaseService<Child1VM> child1Service = new Child1Service();
        IBaseService<IBaseVM>[] services = new IBaseService<IBaseVM>[]
            {
                child1Service,
            };
    }
}