C#泛型-我能从两种选择中选择一种吗?

C#泛型-我能从两种选择中选择一种吗?,c#,.net,class,generics,class-design,C#,.net,Class,Generics,Class Design,假设我有以下类层次结构: Class A {...} Class B : A {...} Class C : A {...} 我现在拥有的是 Class D<T> where T : A {...} D类,其中T:A{…} 但我想要这种形式的东西 Class D<T> where T in {B,C} D类,其中T在{B,C} 这是由于一些奇怪的行为,我不负责B和C有不在A中的通用方法,但如果能够在t上的D中调用它们,那就太好了 注意:我无权访问A、B或C

假设我有以下类层次结构:

Class A {...}

Class B : A  {...}

Class C : A {...}
我现在拥有的是

Class D<T> where T : A {...}
D类,其中T:A{…}
但我想要这种形式的东西

Class D<T> where T in {B,C}
D类,其中T在{B,C}
这是由于一些奇怪的行为,我不负责B和C有不在A中的通用方法,但如果能够在t上的D中调用它们,那就太好了


注意:我无权访问A、B或C来编辑它们

B和C实现相同的接口吗?这可能是一个更好的方法。

您需要为B和C中的常用方法定义一个接口(我们称之为Ibc),使B和C实现此接口,然后您可以编写:

Class D<T> where T : A, Ibc {...}
D类,其中T:A,Ibc{…}
一些选项:

  • 制作一个接口
    idedrivedfroma
    ,其中包含
    B
    C
    中的常用方法
    从你的问题看来这是不可能的
  • D
    cast
    T
    to
    dynamic
    中,动态调用方法
    如果你能使用.NET4,这是最简单的解决方案
  • D
    中,测试您是否处理
    B
    C
    、转换和调用
    将由编译器检查,并且可以从.Net 2进行检查
  • :为
    B
    C
    创建
    D
    的具体实现,它们可以直接从
    B
    C
    调用方法。(我自己没想到这个)。
    仅当“用户源”知道它处理的是
    B
    C
    ,并且不使用摘要
    A
    来使用
    D
    时,才会起作用。相反,它应该使用
    DB
    DC
    。但我认为是这样的,否则你不需要泛型
  • C#中的where约束不允许您选择指定多个类。 此外,如果要指定多个where contains,则必须同时满足这两个条件。对于约束,没有OR逻辑。 以下是规格说明:


    格泽尼奥的回答似乎适合你。将公共行为提取到B和C的公共接口中。然后可以将该接口用作约束。

    这不是直接可行的

    正如其他人所建议的,您可以定义一个接口并在
    B
    C
    中实现它

    如果这不是一个选项(例如,如果这些类超出了您的控制范围),那么我可能会建议这样做:首先,从一个抽象类开始,该抽象类包含从
    A
    派生的任何
    t
    可以实现的所有功能。然后假设你有一些方法,既适用于
    B
    也适用于
    C
    ,它们不是
    a
    的一部分。在
    D
    中,可以通过子类实现这些抽象方法:

    public abstract class D<T> where T : A
    {
        protected T _member;
    
        public void DoSomethingAllTsCanDo()
        {
            _member.DoSomething();
        }
    
        public abstract void DoSomethingOnlyBAndCCanDo();
    }
    

    由于您无法访问源代码,唯一真正的答案(除非您愿意使用
    动态
    )是明确检查
    B
    /
    C
    和cast。

    首先,如果B和C有共同的方法,这是一个设计缺陷,它们不共享接口。也就是说,即使没有访问B和C的权限,您也可以修复此问题。
    可以创建一个公共接口。假设你有:

    public class A
    {
    }
    public class B : A
    {
        public void Start() { }
    }
    public class C : A
    {
        public void Start() { }
    }
    
    您可以创建一个公共接口:

    public interface IStartable
    {
        void Start();
    }
    
    并将其用于B和C的派生类:

    public class BetterB : B, IStartable
    {
    }
    public class BetterC : C, IStartable
    {
    }
    

    如果按原样获得B和C实例,则可能无法实现这一点,但如果创建它们,则可以考虑这样做。事实上,对于专门的B和C类,您可以使用接口而不是
    D

    ,但是,他不控制源A、B和C。这将使此解决方案有点难以实现。啊,我还没有看到编辑。如果这样的接口不存在,那么就我所知,没有直接的方法来实现D类。+1-这是首选的解决方案。我补充了一个答案,说明在某些情况下如何做到这一点。很奇怪你得到了公认的答案@Jean Bernard Pellerin-你能解释一下你是如何解决的吗?事实上,最后我没有使用你的任何一个答案。我给一个被真实方法覆盖的扩展方法添加了一个:)我喜欢这个答案。它还提供了一个更通用的解决方案,其中没有a,例如,如果B和C来自具有不同来源的库
    public class BetterB : B, IStartable
    {
    }
    public class BetterC : C, IStartable
    {
    }