С# не может передавать объект в интерфейс в методе с несколькими общими параметрами

Я играю с Generics и в методе с двумя генерическими параметрами пытаюсь применить объект к интерфейсу, который не работает. Следующий код демонстрирует проблему:

private void GenericMethod<t, u="">() 
 where T : Block
 where U : IBlock
 {
 var list = new List<t>();

 // this casting works
 var item = new Block();
 var iItem = (IBlock)item;

 foreach (var l in list)
 { 
 // this doesn't compile
 var variable = (U)l;
 }
 }
</t></t,>

Здесь Block - это класс, а интерфейс IBlock реализован этим классом.

Почему кастинг (U) l терпит неудачу? Как мне это сделать?

4 ответа

Если T наследуется от Block и U из IBlock, это не значит, что T наследует от U, даже если Block наследуется от IBlock. Например:

public class TBlock : Block
{
 public void NewMethod() {}
}

public interface ******* : IBlock
{
 void AnotherNewMethod();
}

Чтобы этот пример работал, вам придется изменить

where T : Block
where U : IBlock

в

where U : IBlock
where T : Block, U

чтобы убедиться, что T наследуется от U.


Вы можете использовать свой итератор. https://dotnetfiddle.net/FgKdL8

using System;
using System.Collections.Generic;

public class Program
{
 public static void Main()
 {
 Console.WriteLine("Hello World");
 }

 private void GenericMethod<t, u="">() 
 where T : Block
 where U : IBlock
 {
 var list = new List<u>();

 // this casting works
 var item = new Block();
 var iItem = (IBlock)item;

 // cast your iterator
 foreach (U l in list)
 { 

 }
 }

 public interface IBlock
 {}
 public class Block : IBlock
 {}
}
</u></t,>


Хотя вы можете конвертировать T в IBlock, вы не можете знать, будет ли он конвертируемым в U, насколько это возможно - U реализует IBLock, но может быть любым типом.


Если вы можете гарантировать, что T наследует U, вы можете добавить это ограничение к объявлению:

where U : IBlock where T : Block, U

Если вы хотите, чтобы функция по-прежнему работала в любом случае, но, если это возможно, приложите к U (я не могу себе представить, зачем вам это нужно, но...), вы можете сделать это:

public GenericMethod<t, u="">()
 where T : Block
 where U : class, IBlock // must be a class to use the 'as' operator 
{
 // ... 
 var variable = item as U;
} 
</t,>

licensed under cc by-sa 3.0 with attribution.