2009-10-22 2 views
0

Что у меня есть?C# Проблема с дженериками

У меня есть абстрактный класс, QueryExecutor и производный класс, SqlQueryExecutor, показанный ниже.

abstract class QueryExecutor<T> 
{ 
    public abstract T Execute(); 
} 

class SqlQueryExecutor<T> : QueryExecutor<T> where T:ICollection 
{ 
    public override T Execute() 
    { 
     Type type = typeof(T); 

     // Do common stuff 
     if (type == typeof(ProfileNodeCollection)) 
     { 
      ProfileNodeCollection nodes = new ProfileNodeCollection(); 
      // Logic to build nodes 
      return (T)nodes; 
     } 
     else 
     { 
      TreeNodeCollection nodes = new TreeNodeCollection(); 
      Logic to build nodes 

      return (T)nodes;     
     } 
    } 
} 

Что я хочу делать?

В реализации метода Execute(), я хочу построить соответствующий объект ICollection и вернуть его.

С какой проблемой сталкиваюсь я?

В Execute() методы, линия, return (T)nodes; показывает следующую ошибку компиляции времени:

Cannot convert type 'WebAppTest.ProfileNodeCollection' to 'T'

Любая идея, как я могу решить эту проблему?

Заранее благодарен!

+0

Вы уже задавали этот вопрос час назад: Дизайн Проблема - общий базовый класс и различные типы возврата: http://stackoverflow.com/questions/1605659/design-problem-common-base-class-and- different-return-types –

+4

Я не уверен, почему возникает проблема, но это такое злоупотребление дженериками, от которых я вообще не хочу отвечать ... Весь смысл дженериков в том, что они должны быть * generic * и не должны содержать особого поведения для разных конкретных типов 'T' (подробнее см. Принцип замещения Лискова). Если вы делаете такие вещи, вам будет лучше с «ProfileNodeCollectionQueryExecutor» и «TreeNodeCollectionQueryExecutor» в качестве отдельных классов (т. Е. Если ваша ситуация требует полиморфизма, а затем используйте его). –

+0

@ Mitch Wheat: Я попытался выполнить ответ на предыдущий вопрос и получил здесь удар. Мысль об обновлении того же вопроса, но я отметил это как ответ. Итак, возник еще один вопрос. Хотя, этот вопрос касается реализации части предыдущего вопроса. – Vijay

ответ

4

Ну, простой способ фиксации это просто сделать компилятор менее известно о том, что происходит, так что это будет просто перенести его в CLR:

return (T)(object)nodes; 

Вы можете поместить это в одном месте и использовать неявное преобразование в object по заданию:

object ret; 
// Do common stuff 
if (type == typeof(ProfileNodeCollection)) 
{ 
    ProfileNodeCollection nodes = new ProfileNodeCollection(); 
    // Logic to build nodes 
    ret = nodes; 
} 
else 
{ 
    TreeNodeCollection nodes = new TreeNodeCollection(); 
    Logic to build nodes 

    ret = nodes; 
} 
return (T)ret; 

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

1

Я бы выбрал здесь отдельные проблемы. У вас может быть даже фабрика QueryExecutor, которая обеспечивала бы право QueryExecutor соответственно типу коллекции.

class ProfileSqlQueryExecutor : QueryExecutor<ProfileNodeCollection> 
{ 
    public override ProfileNodeCollection Execute() 
    { 
     ProfileNodeCollection nodes = new ProfileNodeCollection(); 
     // Logic to build nodes 
     return nodes; 
    } 
} 

class TreeSqlQueryExecutor : QueryExecutor<TreeNodeCollection> 
{ 
    public override TreeNodeCollection Execute() 
    { 
     TreeNodeCollection nodes = new TreeNodeCollection(); 
     Logic to build nodes 
     return nodes;     
    } 
} 
Смежные вопросы