2012-10-22 96 views
8

每当我读到RE或者静态继承的类似主题时,答复通常都不支持(我们知道这一点),并且给出原因是因为这是一个糟糕的设计,可能有更好的方法来做到这一点。我很想找到一个更好的方式来做这件事,所以我愿意接受所有的建议 - 这就是我正在做的。C#替代虚拟静态方法和静态子类

我有一个没有实例数据的类。所有的方法都是静态的。我们称之为class BaseStatic。我现在想要一个新的静态类(当然好几个,但让我们坚持一个)继承这个静态类并添加一些新的静态方法,我们称之为SubStatic

我希望消费者能写的是:

SubStatic.MethodFromSub(); 

SubStatic.MethodFromBase(); 

我知道我也可以这样写:

BaseStatic.MethodFromBase() 

明确,但随后消费者知道哪些类实现了哪些方法。我不能用继承来做到这一点,因为我不能从另一个静态类继承。那么做一个更好的方法是什么?

现在,我知道我能有这些类的实例类,我可以定义的所有方法静态 - 这会给我我上述的行为,但会导致其他问题,即:

  1. 当我这样做:SubStatic.MethodFromBase()因为该方法是在父静态类运行(父的静态构造函数被调用)

  2. 如果静态父方法之一,需要调用其它方法SubStatic静态构造函数不叫哪子类可以覆盖,我需要一个虚拟的静态方法在子类中。我知道我不能拥有。

这么差的设计显然 - 任何人都可以帮我重做吗?我知道我可以使用实例继承并正确使用虚拟方法(我以这种方式工作),但客户端代码总是需要创建一个实例(或者我想某个单例)。

+1

您可以使用单例设计模式创建实例并将其返回给用户。这不会帮助你解决你的问题吗? – manman

+0

是的 - 但是我仍然在创建一个实例,不是吗?此外,消费者将不得不编写:SomeClass.Instance.SomeMethod(),对吗? – RBrowning99

+0

是的,你必须创建实例,但只有一次,然后你可以通过使用Lazy Loading模式来缓存它们。这是你可以继承的唯一方法。此外,这将导致更灵活的代码。 – manman

回答

4

这可以达到你的目的,但我肯定会包括一些异常处理,并伴随它的实现,并附有大量关于它为什么以及如何工作的文档。

Base的静态构造函数运行(一次)时,编目当前加载到应用程序域中的所有程序集,并选择从Base派生的类型。迭代这些,我们运行静态构造函数。值得注意的是,这不再保证每个实现的cctor只会运行一次,必须添加逻辑才能重新做出该断言。此外,对于该Base cctor已运行后,可以进行装载的类型将不被调用在Base

初始化方法来模拟虚拟方法,使用new关键字隐藏基方法。您可以通过(在本例中B类等)与声明类的名称限定它

using System; 
using System.Linq; 
using System.Runtime.CompilerServices; 

namespace ConsoleApplication6 
{ 
    public class Base 
    { 
     static Base() 
     { 
      Console.WriteLine("Base cctor"); 

      var thisType = typeof (Base); 
      var loadedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()); 
      var derivations = loadedTypes.Where(thisType.IsAssignableFrom); 

      foreach(var derivation in derivations) 
      { 
       RuntimeHelpers.RunClassConstructor(derivation.TypeHandle); 
      } 
     } 

     public static void Foo() 
     { 
      Console.WriteLine("Bar"); 
     } 
    } 

    public class A : Base 
    { 
     static A() 
     { 
      Console.WriteLine("A cctor"); 
     } 
    } 

    public class B : Base 
    { 
     static B() 
     { 
      Console.WriteLine("B cctor"); 
     } 

     public new static void Foo() 
     { 
      Console.WriteLine("Bar!!"); 
      Base.Foo(); 
     } 
    } 

    class Program 
    { 
     static void Main() 
     { 
      Console.WriteLine("A:"); 
      A.Foo(); 
      Console.WriteLine(); 
      Console.WriteLine("B:"); 
      B.Foo(); 
      Console.WriteLine(); 
      Console.WriteLine("Base:"); 
      Base.Foo(); 
      Console.ReadLine(); 
     } 
    } 
} 

编辑调用基方法

另一种选择在于CRTP(或CRGP在C#范例),或好奇地重复模板(通用)参数模式

using System; 
using System.Runtime.CompilerServices; 

namespace ConsoleApplication6 
{ 
    public class Base<T> 
     where T : Base<T> 
    { 
     static Base() 
     { 
      RuntimeHelpers.RunClassConstructor(typeof (T).TypeHandle); 
     } 

     public static void Foo() 
     { 
      Console.WriteLine("Bar"); 
     } 
    } 

    public class Base : Base<Base> 
    { 
    } 

    public class A : Base<A> 
    { 
     static A() 
     { 
      Console.WriteLine("A cctor"); 
     } 
    } 

    public class B : Base<B> 
    { 
     static B() 
     { 
      Console.WriteLine("B cctor"); 
     } 

     public new static void Foo() 
     { 
      Console.WriteLine("Bar!!"); 
      Base<B>.Foo(); 
     } 
    } 

    class Program 
    { 
     static void Main() 
     { 
      Console.WriteLine("A:"); 
      A.Foo(); 
      Console.WriteLine(); 
      Console.WriteLine("B:"); 
      B.Foo(); 
      Console.WriteLine(); 
      Console.WriteLine("Base:"); 
      Base.Foo(); 
      Console.ReadLine(); 
     } 
    } 
} 

在这种情况下,当我们调用静态方法上A我们真正调用它Base<A>这是不同于Base<B>Base因此我们可以实际上确定如何调用该方法并运行适当的cctor。

+0

嗯 - 非常聪明,但我会看到的一个问题是所有静态子类构造函数都会被调用 - 我可能有100个这样的子类,这将是浪费。有趣的是,人们正在建议做出这种工作的方式,而不是告诉为什么设计不好。 – RBrowning99

+0

@ RBrowning99这就是为什么我问你是否可以,如果所有的派生类cctors被调用虽然;) – mlorbetske

+0

我误解了你的问题 - 我认为你是关心我是否关心是否调用父类或子类构造函数。抱歉。 – RBrowning99

2

您可以通过使用泛型来实现此目的。例如,您可以使用类似的东西:

public class MainStatic<T> where T : MainStatic<T> 
{ 
    public static void Foo() 
    { 
    } 

    static MainStatic() 
    { 
     RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); 
    } 
} 

public class SubStatic : MainStatic<SubStatic> 
{ 
    public static void Bar() 
    { 
    } 
} 

public class Instance 
{ 
    public void FooBar() 
    { 
     SubStatic.Foo(); 
     SubStatic.Bar(); 
    } 
} 
+0

当您在SubStatic上调用'Foo'时,不会调用SubStatic上的静态构造函数(cctor)。这是OP的问题之一,当调用基本静态成员时,如何强制cctor运行。 – mlorbetske

+0

确实,我不好,我没有检查这个。我会看看我能否改变这一点。 – Guillaume

+0

看到我的答案,你只需要调用'RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle);' – mlorbetske