Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C“课堂设计-我可以用什么来代替“课堂设计”;静态摘要;?_C#_Design Patterns - Fatal编程技术网

C# C“课堂设计-我可以用什么来代替“课堂设计”;静态摘要;?

C# C“课堂设计-我可以用什么来代替“课堂设计”;静态摘要;?,c#,design-patterns,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 } } publ

我想做以下几件事

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; }
    }
}
但是我不能,因为你

我明白为什么我不能这样做——有没有什么能达到相同效果的设计建议

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

您根本无法使
DoSomeMagic()
与当前的设计配合使用。源代码中对MyConcreteClass.DoSomeMagic的调用将被翻译成IL中的MyAbstractClasss.DoSomeMagic。最初使用MyConcreteClass调用它的事实已经丢失


您可以考虑使用一个并行类层次结构,它具有相同的方法,但它是虚拟的——然后将原始类的每个实例与包含先前静态成员的类的实例关联起来…每个选项可能只有一个实例。

不是这个选项的超级粉丝,而是

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


您将错误从编译时转移到运行时,这有点难看

最好的选择是仅使用setter使用带有MagicId的接口

public interface IMagic
{
    int MagicId { get; }
}
根据静态意义的本质,只有一个(是的,就像Highlander一样),你不能覆盖它们

使用接口假定您的客户将实现合同。如果他们想为每个变量创建一个实例或返回一个静态变量的值,则由他们自己决定


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

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


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

单例模式可能会工作吗?MSDN文章的链接,介绍如何在C#中实现单例:

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


只是想一想:)

为什么不让它成为一个非静态的成员呢?

我会质疑是否有“充分的理由”让抽象成员成为静态的

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

考虑
IList.IsFixedSize
属性。这实际上是属于
IList
类型的属性,而不是任何特定实例(即,任何
T[]
都将是固定大小;它不会随
T[]
的变化而变化)。但它仍然应该是实例成员。为什么?由于由于多种类型可以实现IList,因此会因IList的不同而有所不同

考虑一些采用任何
MyAbstractClass
(来自您的示例)的代码。如果此代码设计正确,在大多数情况下,它不应该关心它实际处理的是哪个派生类。重要的是
MyAbstractClass
公开的内容。如果将某些抽象成员设置为静态,基本上访问它们的唯一方法如下:

int magicId;
if (concreteObject is MyConcreteClass) {
    magicId = MyConcreteClass.MagicId;
} else if (concreteObject is MyOtherConcreteClass) {
    magicId = MyOtherConcreteClass.MagicId;
}
为什么这么乱?这样好多了,对吧

int magicId = concreteObject.MagicId;

但也许你还有其他我没有想到的好理由。

听起来像是一个单一国家,也许

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


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

我想知道“好的理由”是什么是-因为它们可能会影响从这里开始的最佳方式。您能否分享拥有此属性的好理由
static
,以便我们更好地了解您的场景并提出解决方案。现在还不清楚你想要实现什么。这真的取决于你想要做什么。你知道我现在想知道我自己现在的“好理由”是什么,我想我可能正在为此努力。。。该类中有一些对象的创建成本非常高,但在使用MagicId的类实例时它们可以保持静态,或者我需要一个单例?或者也许我需要放下这个,明天重新开始;)抽象意味着每个类都必须实现它。静态意味着所有类只有一个实例。因此,这些想法从根本上是对立的,不可能一起创造。如果必须有一些静态值,为什么不通过基本抽象类中的受保护属性公开它们呢?私有静态int val=0;受保护的静态int MagicId{get{return val;}}您不能覆盖静态成员。使用接口如何使我比非静态抽象更进一步?事实上,更糟糕的是编译器没有强制具体类实现接口。是的,我理解为什么我不能做上面的事情-我的问题是什么是正确的设计。@Ryan:这就是为什么我也包括了第二段:)哪个成员-或者所有成员?