Полиморфный базовый класс с неполиморфными дочерними классами и абстракцией - PullRequest
0 голосов
/ 30 января 2019

Предположим, у меня есть TemplateEngine с тремя классами:

  • TemplateEngine
  • TemplateBase<T> where T : TemplateDataBase
  • TemplateDataBase

и пример реализации:

  • SampleTemplate : TemplateBase<SampleTemplateData>
  • SampleTemplateData : TemplateDataBase

и теперь, в двигателе, функция геттера:

public T GetTemplate<T, U>() where T: TemplateBase<U>, new() where U : TemplateDataBase
{
    var template = new T();
    ...
    return template;
}

Поскольку все реализации TemplateBase будут иметь ровно одно действительное значение для U, как и в примере, тип U можно определить с помощью выбора T, и я не должендолжен предоставить это методу GetTemplate.

Другие классы TemplateData содержат совершенно разные данные, и нельзя использовать неправильный класс TemplateData для определенного шаблона.

Если я сейчас удалю тип Uпараметр из вызова функции, я получаю «Неверное количество параметров типа», или, если я удаляю его из определения функции, получатель больше не действителен, потому что «Не удается разрешить U».

Если я сохраню параметр, мне все равно не разрешено это делать, потому что «не существует неявного преобразования ссылок из SampleTemplate в TemplateBase<TemplateDataBase>».

Что я делаю здесь неправильно

1 Ответ

0 голосов
/ 30 января 2019

Поскольку вы пытаетесь использовать параметр типа, который является дочерним по отношению к параметру типа, определенному в методе GetTemplate, вам нужно будет использовать параметр ковариантного типа.Который по определению

Позволяет вам использовать более производный тип, чем первоначально указанный

И поскольку изменения дисперсии могут применяться только к интерфейсам или делегатам, вам необходимосоздать один из двух.Вот пример использования универсального интерфейса с ковариантным параметром типа , который позволяет подразумевать параметр типа:

interface ITemplate<out T> where T : TemplateDataBase
{
    Type DataType { get; }
}

class TemplateBase<T> : ITemplate<T> where T : TemplateDataBase
{
    public Type DataType => typeof(T);
}

class TemplateDataBase { }

class TemplateEngine
{
    public T GetTemplate<T>() where T : ITemplate<TemplateDataBase>, new()
    {
        var template = new T();
        return template;
    }
}

class SampleTemplate : TemplateBase<SampleTemplateData> { }

class SampleTemplateData : TemplateDataBase { }

Обратите внимание на ITemplate<out T>.Это то, что фактически говорит о том, что параметр типа является ковариантным.

А вот пример сайта использования, где выводится тип:

static void Main(string[] args)
{
    var engine = new TemplateEngine();
    var sampleTemplate = engine.GetTemplate<SampleTemplate>();

    Console.WriteLine($"{sampleTemplate.DataType.Name}");
    Console.ReadLine();
}

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...