Вопрос

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

public class SomeClass<T>
{
    public virtual void SomeMethod(){ }
}

public class DeriveFrom :SomeClass<string>
{
    public override void SomeMethod()
    {
        base.SomeMethod();
    }
}

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

public class ClientCode
{
    public void DoSomethingClienty()
    {
        Factory factory = new Factory();
        //Doesn't compile because SomeClass needs a type parameter!
        SomeClass someInstance = factory.Create();

        someInstance.SomeMethod();
    }
}

Кажется, что как только вы введете Generic в иерархию наследования или интерфейс, вы больше не сможете использовать это семейство классов полиморфным образом, за исключением, возможно, внутреннего по отношению к себе.Это правда?

Это было полезно?

Решение

Насколько я понимаю, для использования кода не нужны особенности универсального класса (т. е. это не зависит от того, какой T является).Итак, почему бы вам не представить интерфейс, который SomeClass<T> будет реализовывать и использовать экземпляр этого интерфейса.

Например.:

public interface ISome
{
    void SomeMethod();
}

public class SomeClass<T>: ISome
{
    public virtual void SomeMethod(){ }
}

public void DoSomethingClienty()
{
    Factory factory = new Factory();
    ISome someInstance = factory.Create();

    someInstance.SomeMethod();
}

Теперь подклассы SomeClass<T> может работать по-разному на разных Ts, но потребляющий код не изменится.

Другие советы

Я думаю, вы неправильно понимаете суть дженериков. Обобщения позволяют вам обобщать класс, который требует тип, но не особенно заботится о том, что это за тип. Например, List<string> - это список строк, но что будет List? Это довольно бесполезная концепция, чтобы иметь список из ничего.

Каждый специализированный класс (т. е. typeof(List<>)) имеет свой собственный отдельный тип , и компилятор рассматривает его как таковой. возможно получить сам универсальный тип (например, <=>), но в большинстве случаев он бесполезен, и вы определенно не можете создать его экземпляр.

Я бы предпочел использовать абстрактный класс в качестве основы для всех универсальных типов.

public abstract class SomeClass 
{
    public abstract void SomeMethod();
}

public class SomeClass<T> : SomeClass
{
    public override void SomeMethod() { }            
}

public class DeriveFrom<String> : SomeClass<String>
{
    public override void SomeMethod() { base.SomeMethod(); }            
}
  

Кажется, что после того, как вы ввели Generic в иерархию или интерфейс наследования, вы больше не можете использовать это семейство классов полиморфным способом

Правильно, это очень похоже на эту ситуацию:

class StringContainer
{
}

class IntContainer
{
}

StringContainer container = new IntContainer(); // fails to compile

но вы могли бы сделать это:

class Container
{
}

class Container<T> : Container
{
}

Container container = new Container<String>(); // OK

Я думаю, что вы ищете:

  SomeClass(of someType) someInstance = factory(of someType).Create();
or maybe
  SomeClass(of someType) someInstance = factory.Create(of someType)();
or
  SomeClass(of someType) someInstance = factory.Create();

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

public Class ReflectionReport<T> 
{
    // This class uses Reflection to produce column-based grids for reporting.  
    // However, you need a type in order to know what the columns are. 
}

... so, in another class you have...

public Class ReflectionReportProject {
    ReflectionReport<Thang> thangReport = new ReflectionReport<Thang>(); 
    ReflectionReport<Thong> thongReport = new ReflectionReport<Thong>(); 



    ... some more stuff ...

    // Now, you want to pass off all of the reports to be processed at one time....
    public ReflectionReport<????>[] ProvideReports() 
    {
        return new ReflectionReport<????>[] { thangReport, thongReport } ;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top