【问题标题】:why does explicit cast for generic list not work为什么通用列表的显式强制转换不起作用
【发布时间】:2012-04-11 02:15:48
【问题描述】:

我正在尝试在派生类 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;
        }

    }

Segments 在通用基类 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; }

 }

【问题讨论】:

  • 您已经提供了 很多 代码 - 您可以尝试将其缩减为一个简短但完整的程序吗?
  • 我意识到......我刚刚在以前的帖子中发现我被要求提供更多代码! :-s
  • 如果您没有提供完整代码,通常会要求您提供更多信息,但简短而完整的代码通常没问题...
  • OK....我认为删除了一些内容以提高可读性。

标签: c# generics casting explicit-conversion


【解决方案1】:

List&lt;InteractionSegment&gt;InteractionSegment 不同。将一种类型的列表转换为另一种类型的列表不会转换每个项目。
你需要做这样的事情:

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

这使用 LINQ to Objects 将 inEdges 中的每个对象转换为 InteractionSegment 对象,并将结果放回列表中,然后分配给 this.Segments

【讨论】:

  • 好的,谢谢。不过我不确定我是否理解其中的原因,因为我认为我所写的明确演员表的目的是为了克服这一点。
  • 您在InteractionSegmentSegment&lt;Node&gt;not 之间编写了一个显式转换,在List&lt;InteractionSegment&gt;List&lt;Segment&lt;Node&gt;&gt; 之间。我的代码仍然需要并使用您的显式转换。
  • 我以为我都写了 - 请检查。
  • @gwizardry:你是对的。我错过了。但是,没有使用此强制转换,因为根据规范它是无效的运算符声明。在the MSDN 中声明“op-type 和 op-type2 中的至少一个必须是封闭类型”。封闭类型为IntersectionSegment,op-type 为List&lt;IntersectionSegment&gt;,op-type2 为List&lt;Segment&lt;Node&gt;&gt;
  • 好的,谢谢。我确实想知道当我对其进行编码时,但由于它没有作为实际的编译器错误消息被拾取,所以我没有重新考虑它。
【解决方案2】:

让我们看一个不那么令人困惑的例子。

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 上几乎每天都会有人问这个问题。寻找“协变和逆变”,你会发现几十个例子。

【讨论】:

  • 我看到动物只是一个变量标签,它访问与上面一行中新的长颈鹿相同的对象。即它只是一个参考。如果是这样,在合法的显式强制转换中创建的新对象会发生什么情况(例如,如果我们为 Animal 而不是 List 创建了一个)?
  • @gwizardry:如果您想将用户定义的显式转换运算符从Animal 转换为List&lt;Animal&gt;,那很好。这样的转换将从任何Animal 转换为List&lt;Animal&gt;,因此您可以将Giraffe 转换为List&lt;Animal&gt;。但结果不会是List&lt;Giraffe&gt;
  • 不,我的意思是长颈鹿对动物。但是我的查询更多是关于如果我们返回一个新对象的逻辑(比如我在上面的转换运算符中所做的)。这是否会改变您对“将此对象视为此类”的描述
  • @gwizardry:演员表既可以表示“将您认为是一种类型的对象视为另一种类型,而不更改它”,也可以表示“在给定表达式的情况下获取所需类型的对象不是那种类型”。你会注意到这两件事是对立的,一方面非常简洁,另一方面又令人困惑。更多想法请见blogs.msdn.com/b/ericlippert/archive/2009/03/19/…
  • @gwizardry:还请注意,您不能进行用户定义的从 Giraffe 到 Animal(或 Animal 到 Giraffe)的转换,因为这将重新定义现有的转换。这在 C# 中是非法的。
【解决方案3】:

它不能仅仅因为List&lt;Segment&lt;Node&gt;&gt; 不是List&lt;IntersectionSegment&gt; 而起作用。如果您想创建后者,您可以使用Cast() 将列表中的每个项目显式转换为您想要的类型:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多