【问题标题】:How to cast a type to a generic interface which has another interface as its generic parameter [duplicate]如何将类型转换为具有另一个接口作为其泛型参数的泛型接口[重复]
【发布时间】:2019-01-15 21:31:08
【问题描述】:

我正在尝试从我的代码中删除多余的 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 / switch case 逻辑。

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

【问题讨论】:

  • 此代码未显示您指定的任何错误。相反,它显示了其他几个错误,例如: 1. Child1VM 道具必须是公共的。 2. Method2必须有返回类型。
  • 我仍然收到一个错误,这些是与问题无关的非常明显的事情。虽然固定..
  • 您遇到了哪个错误?您的代码至少会产生 6 个不同的错误,而且它们都与您的问题无关。
  • 你还没有解决我在第一条评论中告诉你的问题。 Method2 必须有一个返回类型。你不能在接口中定义构造函数。
  • 替换为完整的可编译代码(没有我想要修复的错误)

标签: c# generics interface polymorphism parametric-polymorphism


【解决方案1】:

Child1Service 转换为IBaseService&lt;Child1VM&gt; 是不可能的,除非IBaseService&lt;T&gt; 中的T 被定义为这样的协变:IBaseService&lt;out T&gt;

现在它会给你这个错误:

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

【讨论】:

  • 适用于 Method1()。接口上的type参数可以同时设置为covariantcontravariant吗?这将解决整体问题。
  • @heyNow:一个类型既是协变的又是逆变的是不合逻辑的,原因有二。首先,“out”实际上意味着“不使用逆变”,而“in”实际上意味着“不使用协变”,所以“in and out”意味着不变,而不是既逆变又协变 i>.
  • @heyNow:其次,假设我们有一个既是协变又是逆变的 T。假设我们有I&lt;Frog&gt;。由于它是协变的,因此可以转换为I&lt;Object&gt;。由于它是逆变的,因此可以转换为I&lt;NewspaperEditor&gt; 因此,在这种情况下,I&lt;Frog&gt; 可以转换为I&lt;NewspaperEditor&gt;;在什么可能的情况下这才有意义?其实I&lt;Anything&gt;可以转换成I&lt;AnythingElse&gt;,也就是说没有限制;如果这就是你的意思,说I&lt;Object&gt;
  • @heyNow:在 T 中创建一个既协变又逆变的接口唯一有意义的情况是如果它根本不使用 T,这是不太可能的设想;通常,您创建一个通用接口是因为您对 T 有使用。因此,出于所有这些原因,在同一个参数中创建一个类型既是协变类型又是逆变类型是非法的。当然,使一个类型在一个参数中协变而在另一个参数中成为逆变是完全合法的。以Func&lt;A, R&gt; 为例。
  • 好的,我可以理解为什么。那么这意味着我在 main() 中尝试做的事情是错误的,或者存在更好的方法来做到这一点。你能指点我一些资源吗?我觉得我只是replacing conditional with polymorphism
猜你喜欢
  • 2018-07-23
  • 1970-01-01
  • 2013-01-08
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2020-09-16
  • 2016-10-20
相关资源
最近更新 更多