2012-03-27 3 views
1

Я пытаюсь отобразить список объектов в пределах consturctor для производного класса IntersectionPath следующим образом.Почему явный приведение для общего списка не работает

public class IntersectionPath : Path<IntersectionSegment>, IEnumerable 
    {   

     //Constructors 
     public IntersectionPath() : base() { Verts = null; } 

     public IntersectionPath(List<Intersection> inVerts, List<Segment<Node>> inEdges) : base() 
     { 
      this.Segments = (List<IntersectionSegment>) inEdges; 
     } 

    } 

Сегменты определяются в общем базового классе Path

public class Path<T> : IEnumerable<T> where T : Segment<Node> 
    { 
     //public properties 
     public List<Direction> Directions {get; set; } 
     public List<T> Segments { get; set; } 
    } 

Я определил явный оператор для броска в классе IntersectionSegment (см ниже и поэтому я неясно, почему это не будет .. компилировать у меня есть сообщение об ошибке для литья в конструкторе IntersectionPath

public class IntersectionSegment : Segment<Intersection> 
{   
    //curves which intersect the primary curve at I0(Start Node) and I1(End Node) 
    public Curve C0 { get; set; } 
    public Curve C1 { get; set; } 

    public IntersectionSegment():base() {} 

    public IntersectionSegment(Intersection n0, Intersection n1):base(n0,n1){} 

    public static explicit operator IntersectionSegment(Segment<Node> s) 
    { 
     if ((s.Start is Intersection) && (s.End is Intersection)) 
     { 
      return new IntersectionSegment(s.Start as Intersection,s.End as Intersection); 
     } 
     else return null; 
    } 

    public static explicit operator List<IntersectionSegment>(List<Segment<Node>> ls) 
    { 
     List<IntersectionSegment> lsout = new List<IntersectionSegment>(); 
     foreach (Segment<Node> s in ls) 
     { 
      if ((s.Start is Intersection) && (s.End is Intersection)) 
      { 
       lsout.Add(new IntersectionSegment(s.Start as Intersection,s.End as Intersection)); 
      } 
      else return null; 
     } 
     return lsout; 
    } 

сегмента определяется как:

public class Segment <T> : Shape where T : Node 
{ 
    //generic properties 
    public T Start { get; set; } 
    public T End { get; set; } 

} 
+1

Вы здесь указали * много кода - можете ли вы попытаться сократить его до одной короткой, но полной программы? –

+0

Я понимаю, что .... я только что нашел в предыдущих сообщениях, я получил запрос на дополнительный код! : -s – gwizardry

+1

Вы, как правило, получите дополнительную информацию, если вы не указали * полный * код, но короткий и полный обычно нормально ... –

ответ

7

List<InteractionSegment> - это не то же самое, что и InteractionSegment. Выделение списка одного типа в список другого типа не будет отображать каждый элемент.
Вам нужно сделать что-то вроде этого:

this.Segments = inEdges.Select(x => (InteractionSegment)x).ToList(); 

Это использует LINQ к объектам, чтобы бросить каждый объект в inEdges к InteractionSegment объекта и помещает результат обратно в список, который затем назначен this.Segments.

+0

ОК спасибо. Не уверен, что я понимаю рассуждения, хотя, как я думал, суть явного броска, который я написал, заключалась в том, чтобы преодолеть это. – gwizardry

+0

Вы написали явное литье между 'InteractionSegment' и' Сегмент 'и ** не ** между' List 'и' List <Сегмент > '. Ваш явный приведение по-прежнему необходимо и используется моим кодом. –

+0

Я думал, что написал САД - пожалуйста, проверьте. – gwizardry

2

Это не работает просто потому, что List<Segment<Node>> не является List<IntersectionSegment>. Если вы хотите создать позже ваш может использовать Cast() явно отбрасывать каждый элемент в списке типа вы хотите:

this.Segments = inEdges.Cast<IntersectionSegment>().ToList(); 
4

Давайте посмотрим на гораздо менее запутанной. Например,

class Animal {} 
class Giraffe : Animal {} 
class Tiger : Animal {} 
... 
List<Giraffe> giraffes = new List<Giraffe>(); 
List<Animal> animals = (List<Animal>) giraffes; // illegal 

Ваш вопрос: я верю, «почему личность на последней строке незаконна?»

Предположим, что это было законно. Теперь добавим еще одну строку:

animals.Add(new Tiger()); 

Вы можете добавить тигра в список животных, не так ли? Но этот список животных - это фактически список жирафов. В листинге нет копия списка, в ней говорится: «Я хочу рассматривать этот объект как имеющий этот тип». Но так как это позволит вам делать сумасшедшие вещи, такие как включение тигра в список жирафов, мы делаем акты незаконными.

Ваша ситуация - это гораздо более сложная версия той же ситуации.

Этот вопрос задается почти каждый день на StackOverflow. Ищите «ковариацию и контравариантность», и вы найдете десятки примеров.

+0

Я вижу, что животные - это просто метка переменной, которая обращается к тому же объекту, что и жирафы, которые были введены в строку выше. то есть его просто ссылкой. Если это так, что происходит с новым объектом, созданным в законном явном приведении (скажем, если мы создали один для Animal вместо List )? – gwizardry

+0

@gwizardry: если вы хотите сделать пользовательский явный оператор преобразования из 'Animal' в' List ', это нормально. Такое преобразование преобразует из любого 'Animal' в' List ', поэтому вы можете преобразовать' Giraffe' в 'List '. Но результат не будет «List ». –

+0

Нет, я имел в виду Жирафа с животными. Но мой запрос был больше о логике, если мы возвращаем новый объект (например, я делаю это в своих операторах кастингов выше). Означает ли это ваше описание «относиться к этому объекту как к этому типу»? – gwizardry