2014-04-18 4 views
0

Я переименовал вопрос с: «Почему мой UpCast() не компилируется как метод экземпляра, а делает это как расширение?« что-то более полезное для будущего изможденного искателя приключений ».Невозможно преобразовать тип 'T' в 'T'?

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

У меня есть класс контейнера, полученный из ObservableCollection. Только сейчас я пытался написать вентиляционный <> общий метод так, что вместо написания:

Columns = new MegaList<DbTableColumn>(); 
Columns.AddRange(oracleDictionary.ListTableColumns(tableName)); // IEnumerable<OracleColumn> 

// or 

(v.Columns = new MegaList<DbTableColumn>()).AddRange(oracleDictionary.ListTableColumns(tableName)); 

// I could instead write 
Columns = oracleDictionary.ListTableColumns(tableName).UpCast<DbTableColumn>(); 

MegaList является ObservableCollection с некоторыми добавлениями удобных методов, которые я не буду показывать здесь. Поскольку ObservableCollection не имеет ConvertAll(), я пробовал это.

В принципе, почему метод следующего экземпляра не компилируется, но я могу реализовать, казалось бы, эквивалент как метод расширения (указанный внизу), это так?

public class MegaList<T> : ObservableCollection<T> 
{ 
    // ...rest of class snipped... 

    public ObservableCollection<TBase> UpCast<TBase, T>() 
     where TBase: class 
     where T : TBase 
    { 
     var listUpcast = new ObservableCollection<TBase>(); 
     foreach (T t in this.Items) <-- Error 14 Cannot convert type 'T' to 'T' ??? Excuse me? 
      listUpcast.Add(t); 
     return listUpcast; 
    } 
} 

Я думаю, что следующее эквивалентно. Просто обменивается «этим» параметром для свойства OberservableCollection.Items, оба сохраняют тип T. Меня особенно путают из-за ограничения типа, которое указывает, что «T должно быть TBase».

static public ObservableCollection<TBase> UpCast<TBase, T>(this ObservableCollection<T> list) 
     where TBase : class 
     where T : TBase 
    { 
     var listUpcast = new ObservableCollection<TBase>(); 
     foreach (var t in list) 
      listUpcast.Add(t); 
     return listUpcast; 
    } 

UPDATE: Ответ ниже, и я нашел следующее, чтобы быть правдой:

  1. C# имеет общий параметр типа затенения, так же как обычный поле/параметра затенения.
  2. Я не могу написать ограничение типа в общем методе с использованием параметра типа из охватывающего класса из-за (1), и я не думаю, что существует способ ссылаться на тип в типе ограничения, где T - типичный параметр типа.
+0

Можете ли вы опубликовать определение свойства Items. Тип свойства Items не может быть выведен из использования. –

+0

Это стандартное свойство Items в коллекции базового класса. http://msdn.microsoft.com/en-us/library/ms132435(v=vs.110).aspx – codenheim

ответ

1

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

После ночного сна меня осенило, что это просто общий затенение параметров. По-видимому, существует тень общих параметров (я этого не знал, так как я не много писал внутренние классы) и работает так же, как и стандартные параметры. Таким образом, хотя T является параметром типа во внешнем классе, компилятор рассматривает T во внутреннем методе (или классе) как T2, и они не являются одним и тем же типом, поэтому ошибка, которая равна «T, не может быть отнесена к T «потому что я пытаюсь повторить IList с T (который должен работать, если вы посмотрите на него чисто с символического уровня).Ошибка:

public class MegaList<T> : ObservableCollection<T> 
{ 
    public ObservableCollection<TBase> UpCast<TBase, T>() // <-- this T isn't outer T 
     where TBase : class 
     where T : TBase 
    { 
     var listUpcast = new ObservableCollection<TBase>(); 
     foreach (T t in this.Items) // <-- error: Argument type 'T' is not assignable to parameter type 'TBase' 
     listUpcast.Add(t); 
     return listUpcast; 
    } 
} 

И так как я должен был бы обеспечить T в качестве общего параметра, я не могу сдерживать его на внутренний метод, который @hvd поддерживает, так что если кто-то не знает, какой синтаксис, что я не делаю , Я просто откажусь от этого и либо использую литье в методе, либо придерживаюсь метода расширения, где я могу напечатать его.

Я честно не могу решить, является ли это функцией или ограничением. Думаю, это будет зависеть от вашей точки зрения. Надеюсь, это помогает кому-то другому. По крайней мере, компилятор C# должен, вероятно, улучшить сообщение об ошибке, чтобы было очевидное различие между типами. Учитывая, что он объявлен во внешней области (так сказать), я не понимаю, почему типы должны быть перечислены как Foo.T vs Foo.T, я бы подумал, что внутренний T будет находиться в пространстве имен символов внешнего класса , и, следовательно, имеют другое квалифицированное имя типа, например MegaList.T vs MegaList.UpCast.T.

+0

О! Вы правы, я полностью пропустил, что вы определили метод экземпляра как 'UpCast ' вместо 'UpCast '. Это * должно * дать вам предупреждение о компиляторе, но даже если вы получите это предупреждение, легко пропустить, если за ним последуют ошибки. Вы должны принять свой собственный ответ, вы совершенно правы (и я уверен, что C# действительно не поддерживает то, что вы хотите сделать), и я удалю свой неправильный ответ. – hvd

0

Если не определение UpCast метода быть

public class MegaList<T> : ObservableCollection<T> 
{ 
    // ...rest of class snipped... 

    public ObservableCollection<TBase> UpCast<TBase>() 
    { 
     var listUpcast = new ObservableCollection<TBase>(); 
     foreach (var t in this.Items) 
      listUpcast.Add((TBase)t); // <-- error: Argument type 'T' is not assignable to parameter type 'TBase' 
     return listUpcast; 
    } 
} 
+0

Согласно документации, «где T: U» означает «аргумент типа, предоставленный для T, должен быть или получен из аргумент, предоставленный для U ", поэтому у меня есть« где T: TBase ».. похоже, что ваш пример - обратный, нисходящий, нет? В нем говорится, где TBase происходит от T, или я неправильно читаю документы. – codenheim

Смежные вопросы