Есть ли способ заставить производный тип объявить статический метод с определенной сигнатурой? - PullRequest
1 голос
/ 15 октября 2019

Мне нужен способ заставить подкласс одного из моих классов объявить определенный статический метод. Например, безопасная функция типа FromFile или FromStream. Подобно концепции абстрактных методов для нестатического контекста.

Я знаю, что мог бы использовать конструкции, подобные этой:

return (T)typeof(T).GetMethod("FromFile").Invoke(null, new[] { someArgs });

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

Я также знаю, что я мог бы получить все эти методы загрузчика при запуске и сохранить их в статической карте Type-Loader, но все жеэто вызовет исключение только во время запуска приложения.

В этом примере я использую загрузчик текстур, который должен иметь возможность загружать различные типы текстур, если они наследуют один и тот же базовый класс. (OpenGL Texture Wrappers, DX Texture Wrappers, Видео Текстуры и т. Д.)

public abstract class DataContainer<T>
{
    public abstract T Load(object someArgs);

    [...]
}

public class TextureContainer<T> : DataContainer<T> where T : Texture<T>
{
    public override T Load(object someArgs)
    {
        if (/*is currently loaded*/)
            return GetLoadedFile(someArgs);
        else
            return T.FromFile(someArgs);
    }

    [...]
}

Базовый класс для текстуры будет выглядеть примерно так:

public abstract class Texture<T> where T : Texture<T>
{
    //works fine, forces derived class to declare a type safe Clone method
    public abstract T Clone();

    //sadly for static methods I can't do the same
    //so I need another way here
    public static /*abstract*/ T FromFile(object someArgs);
}

Тогда конкретная реализация текстуры будетвыглядят так:

public class DirectXTexture : Texture<DirectXTexture>
{
    //works fine
    public override DirectXTexture Clone()
    {
        throw new System.NotImplementedException();
    }

    //another way needed
    public static /*override*/ DirectXTexture FromFile()
    {
        throw new System.NotImplementedException();
    }
}

Имея эту настройку, вы можете просто получить текстуру, используя следующий код с базовой загрузкой DataContainer и при необходимости выгружая текстуру или выполняя задачу загрузки в фоновом потоке.

static class Program
{
    static void Main(string[] args)
    {
        var container = new TextureContainer<DirectXTexture>();
        var tex = container.Load("some file");
    }
}

Просто для пояснения: у меня уже есть полностью работающая конструкция DataContainer, которая может загружать ресурсы в основных или фоновых потоках и отслеживать экземпляры, которые ссылаются на мои ресурсы, чтобы я мог выгружать их, если они больше никому не нужны. Единственное, что мне нужно, это функциональность создания контейнера для типа ABSTRACT с соответствующими им методами загрузки, поэтому мне не нужно создавать отдельный подкласс для DXTextureContainer, GLTextureContainer, VideoTextureContainer и т. Д.

Надеюсь, вы, ребята, ребятаможет помочь мне здесьЗаранее спасибо!

1 Ответ

1 голос
/ 16 октября 2019

До C # 8.0 нет никакого способа обеспечить это.

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

...