【问题标题】:C# Generics and Generic ConstraintsC# 泛型和泛型约束
【发布时间】:2012-06-13 23:04:15
【问题描述】:

我正在编写一个带有类型参数 T 的通用抽象类 A,我打算用类 B 派生它。

A 有一个数据成员 mX,它是类 C 的一个实例,带有一个通用函数。这个通用函数 GetAllOfType() 有一个类型参数 T。这个类型参数被限制到第三个类 D。GetAllOfType() 搜索 D 实例的容器,其中包括 D 的派生类的实例,并返回T 类型的子集(因此对 D 的约束)。

D 类本身没有特定的数据成员 int mY,但 D 的某些派生类有,例如 E 和 F。

public class D
{
}

public class E : D
{
    public int mY;
}

public class F : D
{
    public int mY;
}

public class C
{
    public T[] GetAllOfType<T>() where T : D
    { ... }
}

public class A<T>
{
    private C mX;
    ...
}

public class B : A<E>
{
    ...
}

这就是我的问题开始的地方:

B 类用来继承和实现 A 类的参数类型是 D 的派生类。我试图在 A 类中编写一个函数 Foo,它通过 GetAllOfType() 枚举并访问类型 E、F 的成员 mY,或任何其他拥有 mY 的成员。

public class A<T>
{
    private C mX;

    protected Foo()
    {
        foreach (var c in mX.GetAllOfType<T>())
        {
            c.mY = 0;
        }
    }
}

public class B : A<E>
{
    public Bar()
    {
        Foo();
    }
}

但是,问题是 GetAllOfType() 受到约束,并且我也因为没有约束 A 类而收到错误。

我尝试过像这样约束 A:

public class A<T> where T : D

但是我遇到了编译时错误:

键入 T' does not contain a definition formY' 并且找不到扩展方法 mY' of typeT'(您是否缺少 using 指令或程序集引用?)

我也尝试过限制多个派生类:

public class A<T> where T : E, F

但是我也遇到了如下错误:

类类型约束“F”必须列在任何其他约束之前。考虑将类型约束移到约束列表的开头

我尝试过切换它们:

public class A<T> where T : F, E

同样,结果是相同的错误,但 F 切换为 E。

我正在尝试的可能吗?我做错了什么?

同样,我无法更改 C、D、E 和 F 类的任何内容。

【问题讨论】:

  • 您尝试过foreach (T c in mX.GetAllOfType&lt;T&gt;()) -- 在这种情况下,您需要将成员mY 移动到您的D 基类中。在public class A&lt;T&gt; where T : E, F 的情况下,如果我没记错的话,代码期望T 实现EF
  • 既然所有派生类都有,为什么不将int mY 添加到class D

标签: c# inheritance generics generic-constraints generic-function


【解决方案1】:

在A的泛型参数上添加约束时,

public class A<T> where T : D

出现第二个错误Type T' does not contain a definition for mY' and no extension method mY' of typeT' could be found (are you missing a using directive or an assembly reference?) 的原因是,不出所料,因为 D 没有 mY,只有派生类 E 和 F。原因

public class A<T> where T : E, F

不起作用是因为您只能指定一个基类类型约束(C# 没有多重继承)。任何进一步的约束都必须是接口,或者像 classnew() 之类的东西

据我所知,如果您真的无法更改这些课程的任何内容,那么您尝试完成的任务可能会非常困难。我可以想到一些丑陋的方式(反射,或大量的演员),但这不是正确的道路。也许我缺少一些聪明的东西。如果您可以引入具有 mY 属性的接口(或中间类),并让 E 和 F 从中继承,那就太好了。然后你可以将 T 限制为那个而不是 D 并且一切都将是 honkey dory。否则,除了运行时,我看不到任何方法可以知道您正在处理哪种D

【讨论】:

  • 反射是确定未使用某种继承形式定义的属性的“正确”方式。它可能不干净,但它可以完成工作。
  • @Guvante 是的,也许称它为丑陋并不公平。我希望找到某种方法来解决问题,而无需求助于运行时检查。
  • 没有运行时检查意味着使用新的(真实的,拥有属性 mY)接口,基本上。如果您需要与 D 的所有还具有属性 mY 的衍生物进行交互,则需要引入公开 mY 的 E 和 F 的共同祖先。它可以是一个抽象类(LocalD,为了论证)或一个接口(IHavemY)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多