Поместить static/const в интерфейс или абстрактный класс C#

Рейтинг: 4Ответов: 2Опубликовано: 18.04.2015

Как можно определить интерфейс или абстрактный класс, который вынудит реализовывать публичную константу (отображаемое пользователям наименование класса, нужно вывести список до того как юзверь тыкнет в заинтересовавший его класс) и статический метод (например GetInstance)?

Ответы

▲ 6Принят

Никак.

Это не поддерживается языком.

Вы можете сэмулировать константу уровня экземпляра класса через свойство с одним лишь геттером:

interface ISomething
{
    string ClassName { get; }
}

Статические методы в интерфейс не вписываются никак, вообще. В текущей концепции вы получаете доступ к статическому объекту по имени класса, а не по экземпляру объекта. А поддержка интерфейсов реализована обычным образом, через таблицы виртуальных методов.

Тем не менее, в будущих версиях языка возможны изменения, разрешающие схожую функциональность (generic-условия на наличие статического метода). Design team языка C# обсуждает эту возможность.


Вот пример того, как динамически проверить наличие статического метода:

interface ISomething
{
}

static class SomethingChecker
{
    public static Func<T> CheckAndGetBuider<T>() where T : ISomething
    {
        var type = typeof(T);
        var builder = type.GetMethod("GetInstance",
                                     BindingFlags.Public | BindingFlags.Static);
        // а есть ли такой метод?
        if (builder == null)
            throw new Exception();
        // а не требует ли метод generic-аргумент?
        if (builder.IsGenericMethod)
            throw new Exception();
        // а не требует ли метод параметров?
        if (builder.GetParameters().Length != 0)
            throw new Exception();
        // а подходящий ли тип результата?
        if (!type.IsAssignableFrom(builder.ReturnType))
            throw new Exception();
        // все проверки пройдены
        return () => (T)builder.Invoke(null, null);
    }
}

Здесь рабочий пример использованием: http://ideone.com/bPyoEf

▲ 2

На уровне языка это реализовать невозможно.

Если вы хотите задать некое свойство для всего класса, то можно вместо статического свойства типа string завести статическое свойство типа IDictionary<Type, string>. Пусть каждый класс в статическом конструкторе записывает в словарь своё название.

Если вы используете dependency injection, то подобное свойство можно добавить как мета-информацию к классу, например, с помощью атрибутов.

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

В целом, возможных реализаций много, и что вы выберете — зависит от вашей конкретной ситуации: как вы используете значение, когда и как создаются экземпляры и т.п.