有没有办法强制C#中的子类中存在静态成员?

有没有办法强制C#中的子类中存在静态成员?,c#,reflection,static,C#,Reflection,Static,对于基于瓷砖的游戏,我使用不同的类来描述不同瓷砖类型的行为。它们(显然)派生自基类。现在我的问题是,有时我需要弄清楚玩家是否有足够的资金来支付升级到某个瓷砖类型的费用 由于瓷砖类型的成本始终保持不变,因此使其保持静态似乎是有意义的。不幸的是,C#似乎不允许使用抽象类或接口来强制在子类中存在这样一个静态字段 我的“解决方案”是使用反射获取这些数据,但在我看来,这相当难看,而且有潜在的危险,因为我可能会忘记其中一个子类中的静态字段,这将导致整个事件 下面的代码片段是我目前拥有的AllowedUpda

对于基于瓷砖的游戏,我使用不同的类来描述不同瓷砖类型的行为。它们(显然)派生自基类。现在我的问题是,有时我需要弄清楚玩家是否有足够的资金来支付升级到某个瓷砖类型的费用

由于瓷砖类型的成本始终保持不变,因此使其保持静态似乎是有意义的。不幸的是,C#似乎不允许使用抽象类或接口来强制在子类中存在这样一个静态字段

我的“解决方案”是使用反射获取这些数据,但在我看来,这相当难看,而且有潜在的危险,因为我可能会忘记其中一个子类中的静态字段,这将导致整个事件

下面的代码片段是我目前拥有的
AllowedUpdates
是一个
列表
,包含磁贴可以升级到的类型

foreach (Type t in AllowedUpdates) {

    // Get the Action Point Cost
    FieldInfo fi = t.GetField ("actionPointCost", BindingFlags.NonPublic | BindingFlags.Static);
    int cost = (int)fi.GetValue (null);

    // Check for any requirements
    bool requirementsFulfilled;
    try {
        // Get the static method that checks the necessary requirements.
        MethodInfo mi = t.GetMethod ("CheckRequirements", new Type[] { typeof(Dictionary<string, ProtoObject>) });
        object[] arguments = { neighbourFields };

        // Invoke this method
        object returnValue = mi.Invoke (null, arguments);
        requirementsFulfilled = (bool)returnValue;
    } catch (ArgumentNullException) {
        // This type has no special requirements, pass it.
        requirementsFulfilled = true;
    } catch (NullReferenceException) {
        // No requirements needed, pass it.
        requirementsFulfilled = true;
    }
}
foreach(在AllowedUpdates中键入t){
//获取行动点成本
FieldInfo fi=t.GetField(“actionPointCost”,BindingFlags.NonPublic | BindingFlags.Static);
int cost=(int)fi.GetValue(null);
//检查是否有任何要求
满足bool要求;
试一试{
//获取检查必要需求的静态方法。
MethodInfo mi=t.GetMethod(“CheckRequirements”,新类型[]{typeof(Dictionary)});
对象[]参数={neighbourFields};
//调用此方法
objectreturnvalue=mi.Invoke(null,参数);
满足的要求=(布尔)返回值;
}捕获(异常){
//此型号无特殊要求,请通过。
满足的要求=真实;
}捕获(NullReferenceException){
//不需要任何要求,通过它。
满足的要求=真实;
}
}

一定有更好的办法。是否存在我忽略的设计模式?

您不能通过抽象基类或接口强制任何派生类上存在
静态
成员

反思不是你最好的选择。在这种情况下,请重新考虑使用
静态
类。您可以将平铺类型的成本设置为只读属性。派生类将被强制实现该属性

public abstract int ActionPointCost { get; }

不,这是不可能的。您可能需要实例化一个实例并使用实例字段/属性(这可能比您当前执行的反射更快)。或者,您可以保留一个存储所需值的
字典

将有关平铺的元数据重构到另一个类层次结构,在这个层次结构中,您有成本等问题。

否。
接口
抽象类
不允许您强制执行

原因是它们附加到这些类的实例而不是它们的定义。Eric Lippert在这方面有一篇很好的帖子,但是我现在找不到这个链接

我认为可以强制执行的一种方法是在应用程序启动时使用
反射。如果每个必须具有特定静态成员的类都没有该成员,则应用程序将失败


另一种方法是使用构建后操作来检查这些约束,如
代码契约
do.

您得出结论,对于这个问题,静态字段是正确的设计选择,但是实现包含非常混乱的反射,以强制接受您的设计选择

我会争辩说,如果实现变得混乱,除了“似乎应该”之外没有任何好处,那么设计是错误的


使其成为必须由构造函数设置的只读实例字段。说真的,这会让你头疼。

为什么不在抽象基类中定义受保护(非抽象)的静态字段呢?这可能会阻止异常,但很危险,因为它可能返回错误的值,因为每个类都应该有自己的特定代价。正因为如此,我想我更喜欢异常,因为它们会立即告诉我我的代码中缺少了一些东西……通过选择列表作为数据结构,您已经接受了反射。我认为您在这里真正需要重新考虑的设计决策是“升级由类型的实例表示”。我觉得这很奇怪。为什么升级不由类升级的实例来表示,它可以具有您想要的任何属性?你似乎在使用运行时机制来表示游戏的语义,这是对类型机制的一种奇怪的使用。首先,让我解释一下,我是一名艺术学校的学生,我从未接受过编程方面的适当培训,所以我所知道的关于编程和/或C#的几乎所有知识都是自学的。所以,请原谅我扭曲的假设和愚蠢的问题……首先,不要担心“愚蠢”的问题;每个人都从一开始的某个时刻开始。你原来的问题是完全合理的。第二,基本上你的新问题归结为“我如何做OO设计?”这是一个难题,没有一个正确的答案。如果你想了解更多面向对象的方法来设计你的应用程序,我会提出另一个问题,而不是试图在评论中进行对话。啊哈,为了让第一条评论更清楚,Eric Lippert很受尊重,但不被认为是一个关键词。似乎是这个问题的自然解决方案。它还允许一个类继承这个属性,如果它的父类已经拥有它(
abstract
意味着你有一个基类和直接的子类-你可能有其他的层次结构,所以你不是真的强迫每个类实现它,但无论如何这可能更好)。所以如果我想得到(假设的)升级的成本,我会使用
Activator.CreateInstance(t)
,获取值并再次销毁实例?(只是检查我是否正确)你应该