【问题标题】:List of static classes in C#C# 中的静态类列表
【发布时间】:2013-07-31 17:16:27
【问题描述】:

我想要一些类,它们都扩展了一个基本抽象类。

然后,我想要拥有每个存储这些类的子集并调用它们实现的方法的对象。

所以我想 - 我对存储的对象什么都不做,所以让我们将这些类设为静态,我不会在存储对象上浪费内存,只是引用静态类,所以我可以调用静态函数。问题是 - 我该怎么做?

对于那些喜欢代码的人,这是我需要的:

public static abstract class A {
    public static abstract void F();
}

public static class B : A {
    public static override void F() {
        ...
    }
}
// Class Storage of course does NOT work, its just here to illustrate what I need
public class Storage {
    private List<A> list;
    public void AddElement(A element) {
        list.Add(element);
    }
    public void DoStuff() {
        foreach(A element in list)
            element::F();
    }
}

有没有办法做这样的事情?或者针对此类问题的不同解决方案?

【问题讨论】:

  • 静态不会浪费内存?..
  • 静态类不能从其他类继承,也不能被继承。您也不能在静态函数上使用覆盖。
  • 听起来你想要一个包含函数的静态类,以及保存数据以传递给这些函数的结构。例如,而不是 void DoStuff()void DoStuff(List&lt;A&gt; list)
  • 与其考虑static,不如考虑使用单例模式,或者查看Lazy&lt;T&gt;

标签: c# oop inheritance static-methods static-classes


【解决方案1】:

不,你不能那样做。您尝试执行的操作存在许多问题:

  1. 您不能使用静态类型作为类型参数——例如List&lt;A&gt;
  2. 您不能使用静态类型作为方法参数,例如AddElement(A element)
  3. 您不能将静态类型抽象化,因为无法从它继承。
  4. 即使在非静态类中,也不能将静态方法抽象化,因为它不能被覆盖。

根据您对问题的描述,我认为这里不需要静态类型或静态方法。只需创建一个简单的抽象类并从中继承即可:

public abstract class A {
    public abstract void F();
}


public class B : A {
    public override void F() {
        ...
    }
}

public class Storage {
    private List<A> list;
    public void AddElement(A element) {
        list.Add(element);
    }
    public void DoStuff() {
        foreach(A element in list)
            element.F();
    }
}

或者,您可以创建一个List&lt;Type&gt; 并使用反射来调用这些类型的静态方法。例如:

public static class A {
    public static void F() { ... }
}
public static class B {
    public static void F() { ... }
}

List<Type> typeList = new List<Type> { typeof(A), typeof(B) };
foreach(var type in typeList)
{
    type.GetMethod("F").Invoke(null, null); 
}

但是使用反射会比使用直接方法调用要慢,而且你会失去所有使用这种方法的类型安全性(除非你自己编写类型检查)。

【讨论】:

  • 你的第一个解决方案正是我最初的想法,问题是,我可以拥有很多具有 B 类对象的存储对象,我觉得我因此浪费了太多内存
  • @user1362083 你是怎么浪费内存的?空类或纯抽象类的实例只占用少量内存。如果它不为空,则必须将该数据存储在某处。
【解决方案2】:

p.s.w.g. 的答案显示了处理您提供给我们的代码的正确方法,但听起来您想要做的是调用方法列表。这些方法没有关联数据,因此您想将它们设为静态类。为什么不使用 Action?

public class Storage {
    private Action list;
    public void AddElement(Action element) {
        list.Add(element);
    }
    public void DoStuff() {
        foreach(Action element in list)
            element();
    }
}

然后你可以将你的方法添加到存储中:

public void DefineStoredFunctions(Storage s)
{
    s.AddElement(() => { first function F });
    s.AddElement(() => { another function F });
    s.AddElement(() => A.F()); //or just call function defined on A
    s.AddElement(B.F); //or get rid of lambda altogether
    //and so on...
}

编辑:如果这不是您想要的,您应该采用其他答案的方法并使用普通对象

【讨论】:

  • +1 这是一个很好的方法(比我的反射示例更好),但没有理由需要使用 lambdas。如果您定义静态类AB,您可以简单地使用s.AddElement(A.F) / s.AddElement(B.F)
  • 是的,我在发帖后才意识到。现在有几种使用语法编辑的可能方式。
【解决方案3】:

这个想法有很多问题:

  • 静态类只有一个实例,只能在“静态上下文”中访问。您不能定义静态类,然后将其添加为列表的元素。

  • 静态类不能继承,也不能继承自 Object 以外的任何东西(它是隐式的)。

  • 由于继承不适用于静态,因此虚拟或抽象重写方法的概念也不适用于静态。

  • Static 只为它们的代码和任何静态实例状态(字段、属性)使用的内存略少,就像普通对象一样。

只需使用普通对象即可。 “过早的优化是计算机编程中万恶之源——无论如何,大部分都是罪恶的根源”。我想不出比我正在回答的问题更好的例子来说明该陈述的真实性,其中极少的内存节省被用来证明试图打破面向对象设计的基本规则(即最小化 em> 使用静态)。

如果你想获取一个对象的实例,请确保你拥有的实例与其他人的相同(换句话说,只允许存在一个实例),但仍将其视为对象的实例,看看Singleton pattern。 C# 中的 Singleton 可以从其他类继承,也可以从其他类继承,可用的实例正是如此,因此您可以将它传递给其他不必关心它在哪里得到它的代码(例如您的列表),然而您仍然可以从不介意使用静态访问器的任何地方获取该实例,并且可以强制您只有一个。

【讨论】:

    猜你喜欢
    • 2016-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多