Список статических классов в C#

Я хотел бы иметь несколько классов, которые расширяют один базовый абстрактный класс.

Затем я хотел бы иметь объекты, каждый из которых хранит подмножество этих классов и вызывает метод, который они реализуют.

Поэтому я подумал - я ничего не делаю с объектами, которые храню, так что давайте просто сделаем эти классы статическими, и я не буду тратить память на хранение объекта, только ссылки на статические классы, чтобы я мог вызывать статическую функцию. Вопрос - как мне это сделать?

Для тех, кто предпочитает код, вот что мне нужно:

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();
    }
}

Есть ли способ сделать что-то подобное? Или другое решение такой проблемы?


person mpiekarz    schedule 31.07.2013    source источник
comment
Статика не будет тратить память?..   -  person Sayse    schedule 31.07.2013
comment
Статические классы не могут наследоваться от других классов и не могут быть унаследованы от них. Вы также не можете использовать переопределение статических функций.   -  person Magnus Grindal Bakken    schedule 31.07.2013
comment
Похоже, вам нужен статический класс с функциями и структурами для хранения данных для передачи этим функциям. например, вместо void DoStuff() есть void DoStuff(List<A> list)   -  person Shaz    schedule 31.07.2013
comment
Вместо того, чтобы думать static, вы можете изучить использование шаблона singleton или изучить Lazy<T>   -  person Khan    schedule 31.07.2013


Ответы (3)


Нет, ты не можешь этого сделать. Есть ряд проблем с тем, что вы пытаетесь сделать:

  1. Вы не можете использовать статические типы в качестве аргументов типа, например. List<A>.
  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<Type> и использовать отражение для вызова статических методов для этих типов. Например:

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); 
}

Но использование отражения будет медленнее, чем использование прямых вызовов методов, и вы потеряете всю безопасность типов с этим методом (если только вы не напишете проверки типов самостоятельно).

person p.s.w.g    schedule 31.07.2013
comment
ваше первое решение - это именно то, о чем я подумал сначала, дело в том, что у меня может быть много объектов Storage, которые имеют объект класса B, и я чувствую, что из-за этого трачу так много памяти - person mpiekarz; 31.07.2013
comment
@user1362083 user1362083 Как ты тратишь память? Экземпляр пустого или чисто абстрактного класса занимает совсем немного памяти. Если он не пуст, вам нужно где-то хранить эти данные. - person p.s.w.g; 31.07.2013

Ответ p.s.w.g. показывает правильный способ подхода к коду, который вы нам дали, но похоже, что вы хотите сделать, это вызвать список методов. Эти методы не имеют связанных данных, поэтому вы решили сделать их статическими классами. Почему бы не использовать действие?

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...
}

Изменить: Если это не то, к чему вы стремились, вам следует использовать подход других ответов и использовать обычные объекты.

person mao47    schedule 31.07.2013
comment
+1 Это довольно хороший подход (лучше, чем мой пример с отражением), но нет причин нужно использовать лямбда-выражения. Если вы определяете статические классы, A и B, вы можете просто использовать s.AddElement(A.F)/s.AddElement(B.F) - person p.s.w.g; 31.07.2013
comment
Да, я понял после публикации. Сейчас есть несколько возможных способов использования синтаксиса Редактирование. - person mao47; 31.07.2013

В этой идее так много неправильного:

  • Статические классы имеют один и только один экземпляр, к которому можно получить доступ только в «статическом контексте». Вы не можете определить статический класс, а затем добавить его как элемент списка.

  • Статические классы не могут наследоваться и не могут наследоваться ни от чего, кроме Object (что он и делает неявно).

  • Поскольку наследование не работает со статикой, концепция виртуальных или абстрактных переопределенных методов также не работает со статикой.

  • Статика использует лишь немного меньше памяти для своего кода и любого статического состояния экземпляра (полей, свойств), как обычный объект.

Просто используйте обычные объекты. «Преждевременная оптимизация — корень всех зол — во всяком случае, большей их части — в компьютерном программировании». Я не могу придумать лучшего примера истинности этого утверждения, чем вопрос, на который я отвечаю, где крайне небольшая экономия памяти используется для оправдания попытки нарушить основные правила объектно-ориентированного проектирования (а именно, для минимизации использование статического состояния).

Если вы хотите получить экземпляр объекта, убедитесь, что экземпляр, который у вас есть, такой же, как и у всех остальных (другими словами, разрешено существование только одного экземпляра), но по-прежнему относитесь к нему как к экземпляру объекта, посмотрите в шаблоне Singleton. Синглтон в С# может быть унаследован и может наследоваться от других классов, доступный экземпляр именно такой, и поэтому вы можете передать его другому коду, которому все равно, где вы его взяли (например, ваш список), и все же вы по-прежнему можете получить этот экземпляр из любого места, где вы не возражаете против использования статического метода доступа, и вы можете принудительно указать, что у вас есть только один.

person KeithS    schedule 31.07.2013