C#类设计 - 我可以使用什么而不是“静态抽象”?

时间:2010-05-24 19:53:11

标签: c# design-patterns

我想做以下

public abstract class MyAbstractClass
{
    public static abstract int MagicId
    {
        get;
    }

    public static void DoSomeMagic()
    {
        // Need to get the MagicId value defined in the concrete implementation
    }
}

public class MyConcreteClass : MyAbstractClass
{
    public static override int MagicId
    {
        get { return 123; }
    }
}

但是我不能因为你can't have static abstract members

我理解为什么我不能这样做 - 对设计的任何建议都能达到相同的效果?

(为了清楚起见 - 我试图提供一个带有抽象基类的库,但具体版本必须自己实现一些属性/方法,是的,有充分的理由保持它是静态的。)

9 个答案:

答案 0 :(得分:5)

您从根本上无法使DoSomeMagic()与当前设计一起使用。源代码中对MyConcreteClass.DoSomeMagic的调用将转换为IL中的MyAbstractClasss.DoSomeMagic。最初使用MyConcreteClass调用它的事实已经丢失。

您可能会考虑使用具有相同方法但是虚拟的并行类层次结构 - 然后将原始类的每个实例与包含先前静态成员的类的实例相关联......并且应该只有一个实例其中每一个。

答案 1 :(得分:4)

Singleton模式可能会起作用吗?指向如何在C#中实现单例的MSDN文章的链接:

http://msdn.microsoft.com/en-us/library/ff650316.aspx

在您的特定示例中,Singelton实例可以使用您的MagicId扩展一个抽象基类。

只是一个想法:)

答案 2 :(得分:3)

我会质疑使抽象成员静态的“充分理由”。

如果您认为这些成员可能反映派生类本身的某些属性而不是给定的实例,则这并不一定意味着成员应该是静态的。

考虑IList.IsFixedSize属性。这实际上是IList的属性,而不是任何特定实例(即,任何T[]将是固定大小;它不会与{{{{{{ 1}}到另一个)。但它仍然应该是一个实例成员。为什么?由于,因为多种类型可能会实现T[],因此IList变为另一种。

考虑一些带有任何IList的代码(来自您的示例)。如果这个代码设计得恰当,在大多数情况下,它不应该关心它实际处理的派生类。重要的是MyAbstractClass暴露的内容。如果你将一些抽象成员静态化,基本上访问它们的唯一方法就是这样:

MyAbstractClass

为什么这么乱?这好多了,对吗?

int magicId;
if (concreteObject is MyConcreteClass) {
    magicId = MyConcreteClass.MagicId;
} else if (concreteObject is MyOtherConcreteClass) {
    magicId = MyOtherConcreteClass.MagicId;
}

但也许你有其他很好的理由没有发生在我身上。

答案 3 :(得分:2)

您最好的选择是仅使用setter

使用MagicId的界面
public interface IMagic
{
    int MagicId { get; }
}

根据静态意义的本质,只能有一个(是的,像Highlander),你不能覆盖它们。

使用界面假定您的客户将实施合同。如果他们想要为每个实例设置一个实例或者返回一个静态变量的值,则取决于它们。

保持静态的好理由也意味着你不需要在子类中重写它。

答案 4 :(得分:0)

不是这个选项的忠实粉丝,但是......

您可以声明属性static,而不是abstract,virtual并抛出NotImplementedException,它返回一个错误消息,该方法必须在派生类中重写。

您将错误从编译时移动到运行时虽然有点难看。

答案 5 :(得分:0)

实现静态成员继承的语言通过元类来完成(也就是说,类也是对象,这些对象有一个元类,并且通过它存在静态继承)。你可以模糊地将它转换为工厂模式:一个类有魔术成员,可以创建第二类的对象。

那,或者使用反射。但是,您无法在编译时确保派生类静态地实现某个属性。

答案 6 :(得分:0)

为什么不让它成为非静态成员?

答案 7 :(得分:0)

或许听起来像Monostate? http://c2.com/cgi/wiki?MonostatePattern

答案 8 :(得分:0)

例如,ASP.NET成员资格提供程序使用的provider pattern可能就是您要查找的内容。

你不能对静态成员有多态行为,因此你将拥有一个静态类,其成员委托给一个封装多态行为的接口(或抽象类)字段。