Работа с несколькими обобщениями в вызове метода - PullRequest
0 голосов
/ 25 мая 2010

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

abstract class ClassBase<T>
{
    T Property { get; set; }
}

class MyClass : ClassBase<string>
{
    OtherClass PropertyDetail { get; set; }
}

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

class Helper
{
    void HelpMe<C, T>(object Value)
        where C : ClassBase<T>, new()
    {
        DoWork();
    }
}

Это просто простой пример, потому что у меня есть некоторые вызовы методов, в которых список предложений where составляет 5 или 6 строк для обработки всех общих данных. То, что я действительно хотел бы сделать, это

class Helper
{
    void HelpMe<C>(object Value)
        where C : ClassBase, new()
    {
        DoWork();
    }
}

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

Ответы [ 3 ]

2 голосов
/ 25 мая 2010

Я предполагаю, что ваш метод HelpMe будет использоваться для инициализации конкретного типа ClassBase<T> (предположение, основанное на ограничениях). Чтобы сохранить код полностью универсальным (если вам нужно и T, и C где-то в методе), вам, вероятно, нужно сохранить оба параметра типа.

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

abstract class ClassBase { 
   object UntypedProperty { get; set; } 
} 
abstract class ClassBase<T> : ClassBase { 
   T Property { get; set; } 
   public override object UntypedProperty { 
     get { return Property; }
     set { Property = (T)value; }
   }
} 

Тогда вы можете написать вспомогательный метод следующим образом:

void HelpMe<C>(object Value) where C : ClassBase, new() { 
  var n = new C();
  c.UntypedProperty = Value;
} 

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

0 голосов
/ 25 мая 2010

без необходимости передавать ему целый массив универсальных классов для работы функции

Небольшое изменение может облегчить эти звонки. Переместите несколько раз указанные типы в общее объявление класса.

  //before
Helper x = new Helper();
x.HelpMe<MyClass, string>(x);
x.HelpMe<MyClass, string>(y);

  //after
Helper x = new Helper<string>();
x.HelpMe<MyClass>(x);
x.HelpMe<MyClass>(y);



  //the change
class Helper<T>
{ 
    void HelpMe<C>(object Value) 
        where C : ClassBase<T>, new() 
    { 
        DoWork(); 
    } 
} 
0 голосов
/ 25 мая 2010

Обобщения имеют тенденцию распространяться через код, и по этой причине они редко используются в качестве «смешанных» классов.

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

Существует еще одна возможность, кроме редизайна (или дублирования API): dynamic . Если вы хотите потерять IntelliSense в своих вспомогательных методах (и готовы заплатить очень и очень небольшое снижение производительности во время выполнения), вы можете использовать dynamic в своем вспомогательном методе:

class Helper
{
    void HelpMe<C>(object Value)
      //  where C : ClassBase<T>, new() // no longer needed, but should be documented
    {
        dynamic cObj = Activator.CreateInstance<C>(); // instead of "new C()"
        cObj.PropertyDetail = ...;
        cObj.Property = ...;
        ...
    }
}
...