C# 什么';静态方法继承的正确替代方案是什么?

C# 什么';静态方法继承的正确替代方案是什么?,c#,.net,inheritance,static,C#,.net,Inheritance,Static,我知道C#中不支持静态方法继承。我还阅读了一些讨论(包括这里),其中开发人员声称需要此功能,对此的典型响应是“如果需要静态成员继承,那么设计中就存在缺陷” 好的,鉴于OOP甚至不想让我考虑静态继承,我必须得出结论,我对它的明显需求指向了我设计中的一个错误。但是,我被卡住了。我真的很感激你能帮我解决这个问题。这就是挑战 我想创建一个抽象基类(让我们称之为水果),它封装了一些复杂的初始化代码。此代码不能放在构造函数中,因为其中一些代码将依赖于虚拟方法调用 水果将被其他具体类(Apple、Orange

我知道C#中不支持静态方法继承。我还阅读了一些讨论(包括这里),其中开发人员声称需要此功能,对此的典型响应是“如果需要静态成员继承,那么设计中就存在缺陷”

好的,鉴于OOP甚至不想让我考虑静态继承,我必须得出结论,我对它的明显需求指向了我设计中的一个错误。但是,我被卡住了。我真的很感激你能帮我解决这个问题。这就是挑战

我想创建一个抽象基类(让我们称之为水果),它封装了一些复杂的初始化代码。此代码不能放在构造函数中,因为其中一些代码将依赖于虚拟方法调用

水果将被其他具体类(Apple、Orange)继承,每个类都必须公开一个标准的工厂方法CreateInstance()来创建和初始化实例

如果静态成员继承是可行的,我会将工厂方法放在基类中,并使用对派生类的虚拟方法调用来获取必须从中初始化具体实例的类型。客户端代码将简单地调用Apple.CreateInstance()以获得完全初始化的Apple实例


但显然这是不可能的,所以请有人解释我的设计需要如何更改以适应相同的功能。

我认为最好的做法是在必须调用的fruit类上创建一个虚拟/抽象初始化方法,然后创建一个外部“fruit factory”类来创建实例:


public class Fruit
{
    //other members...
    public abstract void Initialise();
}

public class FruitFactory()
{
    public Fruit CreateInstance()
    {
        Fruit f = //decide which fruit to create
        f.Initialise();

        return f;
    }
}

为什么不用create方法创建一个工厂类(模板化的)

FruitFactory<Banana>.Create();
FruitFactory.Create();

将factory方法移出类型,并将其放入自己的factory类中

public abstract class Fruit
{
    protected Fruit() {}

    public abstract string Define();

}

public class Apple : Fruit
{
    public Apple() {}

    public override string Define()
    {
         return "Apple";
    }
}

public class Orange : Fruit
{
    public Orange() {}

    public override string Define()
    {
         return "Orange";
    }
}

public static class FruitFactory<T> 
{
     public static T CreateFruit<T>() where T : Fruit, new()
     {
         return new T();
     }
}
公共抽象类
{
受保护水果(){}
公共抽象字符串Define();
}
公营苹果:水果
{
公共苹果(){}
公共重写字符串Define()
{
返回“苹果”;
}
}
公共级橙子:水果
{
公共橙色(){}
公共重写字符串Define()
{
返回“橙色”;
}
}
公共静态类工厂
{
公共静态T CreateFruit(),其中T:Fruit,new()
{
返回新的T();
}
}
但是,正如我所看到的,没有必要将Create方法移动到它自己的工厂类(尽管我认为它更可取-分离关注点-),您可以将它放在水果类中:

public abstract class Fruit
{

   public abstract string Define();

   public static T CreateFruit<T>() where T : Fruit, new()
   {
        return new T();
   }

}
公共抽象类
{
公共抽象字符串Define();
公共静态T CreateFruit(),其中T:Fruit,new()
{
返回新的T();
}
}
以及,看看它是否有效:

    class Program
    {
        static void Main( string[] args )
        {
            Console.WriteLine (Fruit.CreateFruit<Apple> ().Define ());
            Console.WriteLine (Fruit.CreateFruit<Orange> ().Define ());

            Console.ReadLine ();
        }        
    }
类程序
{
静态void Main(字符串[]参数)
{
Console.WriteLine(Fruit.CreateFruit().Define());
Console.WriteLine(Fruit.CreateFruit().Define());
Console.ReadLine();
}        
}

我会这样做

 public abstract class Fruit() {
      public abstract void Initialize();
 }

 public class Apple() : Fruit {
     public override void Initialize() {

     }
 }

 public class FruitFactory<T> where T : Fruit, new {
      public static <T> CreateInstance<T>() {
          T fruit = new T();
          fruit.Initialize();
          return fruit;  
      }
 } 


var fruit = FruitFactory<Apple>.CreateInstance()
公共抽象类Fruit(){
公共抽象空初始化();
}
公共级苹果():水果{
公共覆盖无效初始化(){
}
}
公共级水果工厂,其中T:水果,新{
公共静态CreateInstance(){
T水果=新的T();
水果初始化();
还果;
}
} 
var fruit=FruitFactory.CreateInstance()
NET BCL中的类及其派生类型代表了一个很好的例子,说明了如何相对较好地实现此类设计

WebRequest
类有几个子类,包括
HttpWebRequest
ftpWebRequest
。现在,这个
WebRequest
基类也是工厂类型,并公开了一个静态方法(实例构造函数是隐藏的,这是工厂模式所要求的)

Create
方法返回
WebRequest
类的特定实现,并使用URI(或URI字符串)确定要创建和返回的对象的类型

这将导致以下使用模式的最终结果:

var httpRequest = (HttpWebRequest)WebRequest.Create("http://stackoverflow.com/");
// or equivalently
var httpRequest = (HttpWebRequest)HttpWebWebRequest.Create("http://stackoverflow.com/");

var ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://stackoverflow.com/");
// or equivalently
var ftpRequest = (FtpWebRequest)FtpWebWebRequest.Create("ftp://stackoverflow.com/");

我个人认为这是解决这个问题的一个好方法,而且它确实似乎是.NET Framework创建者首选的方法。

首先,没有可以是虚拟的静态初始值设定项并不意味着你不能有“标准”成员方法,这可能会过载。其次,您可以从构造函数调用虚拟方法,它们将按预期工作,因此这里没有问题。第三,您可以使用泛型创建类型安全工厂。
下面是一些代码,它使用构造函数调用的factory+member Initialize()方法(它是受保护的,所以您不必担心,有人会在创建对象后再次调用它):


抽象类水果
{
公众水果()
{
初始化();
}
受保护的虚拟空初始化()
{
Console.WriteLine(“Fruit.Initialize”);
}
}
苹果类:水果
{
公共苹果公司()
:base()
{ }
受保护的覆盖无效初始化()
{
base.Initialize();
Console.WriteLine(“Apple.Initialize”);
}
公共重写字符串ToString()
{
返回“苹果”;
}
}
橙色类:水果
{
公共橙
:base()
{ }
受保护的覆盖无效初始化()
{
base.Initialize();
Console.WriteLine(“Orange.Initialize”);
}
公共重写字符串ToString()
{
返回“橙色”;
}
}
高级水果厂
{
公共静态T CreateFruit(),其中T:Fruit,new()
{
返回新的T();
}
}
公共课程
{
静态void Main()
{
苹果=水果工厂。CreateFruit();
Console.WriteLine(apple.ToString());
橙色=新橙色();
Console.WriteLine(orange.ToString());
弗鲁伊
var httpRequest = (HttpWebRequest)WebRequest.Create("http://stackoverflow.com/");
// or equivalently
var httpRequest = (HttpWebRequest)HttpWebWebRequest.Create("http://stackoverflow.com/");

var ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://stackoverflow.com/");
// or equivalently
var ftpRequest = (FtpWebRequest)FtpWebWebRequest.Create("ftp://stackoverflow.com/");

abstract class Fruit
{
    public Fruit()
    {
        Initialize();
    }

    protected virtual void Initialize()
    {
        Console.WriteLine("Fruit.Initialize");
    }
}

class Apple : Fruit
{
    public Apple()
        : base()
    { }

    protected override void Initialize()
    {
        base.Initialize();
        Console.WriteLine("Apple.Initialize");
    }

    public override string ToString()
    {
        return "Apple";
    }
}

class Orange : Fruit
{
    public Orange()
        : base()
    { }

    protected override void Initialize()
    {
        base.Initialize();
        Console.WriteLine("Orange.Initialize");
    }

    public override string ToString()
    {
        return "Orange";
    }
}

class FruitFactory
{
    public static T CreateFruit<T>() where T : Fruit, new()
    {
        return new T();
    }
}

public class Program
{

    static void Main()
    {
        Apple apple = FruitFactory.CreateFruit<Apple>();
        Console.WriteLine(apple.ToString());

        Orange orange = new Orange();
        Console.WriteLine(orange.ToString());

        Fruit appleFruit = FruitFactory.CreateFruit<Apple>();
        Console.WriteLine(appleFruit.ToString());
    }
}
public abstract class Fruit<T>
    where T : Fruit<T>, new()
{
    public static T CreateInstance()
    {
        T newFruit = new T();
        newFruit.Initialize();  // Calls Apple.Initialize
        return newFruit;
    }

    protected abstract void Initialize();
}

public class Apple : Fruit<Apple>
{
    protected override void Initialize() { ... }
}
Apple myAppleVar = Fruit<Apple>.CreateInstance();