为什么这个C#代码示例没有工作?

为什么这个C#代码示例没有工作?

问题描述:

我试图理解为什么这个转换不起作用:为什么这个C#代码示例没有工作?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace CastTest { 

    class Foo {} 

    // I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere. 
    class FooList : List<Foo> {} 

    class Program { 
     static void Main(string[] args) { 
      FooList list = (FooList) Program.GetFooList(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() { 
      return new List<Foo>(); 
     } 
    } 
} 

这会产生一个运行时错误:

InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[CastTest.Foo]' to type 'CastTest.FooList'.

任何人都可以解释为什么这不工作,以及是否我可以以某种方式解决这个问题?

+0

哪一行产生错误? – ChrisF 2012-03-05 22:26:52

+0

这是正确的说:FooList是列表,或列表是FooList? – 2012-03-05 22:29:43

+0

@AnthonyPegram前者。 – hvd 2012-03-05 22:31:33

您无法自动从父类转换为派生类:只是因为你正在试图投的对象是List<Foo>并不一定使之成为FooList

退房:

http://social.msdn.microsoft.com/Forums/is/csharplanguage/thread/f7362ba9-48cd-49eb-9c65-d91355a3daee

你可以写一个List<Foo>转换为FooList操作,可能使用AddRange填充值,如:

class FooList 
{ 
public explicit operator FooList(List<Foo> arg) 
{ 
    FooList result = new FooList(); 
    result.AddRange(arg); 
    return result; 
    } 
} 

此外,最好只使用一个using别名http://msdn.microsoft.com/en-us/library/sf0df423(v=vs.80).aspx

using FooList = List<Foo>; 

这样你实际上并没有绕过不必要的派生类。

+1

也许低调? – user1096188 2012-03-05 22:27:27

+0

谢谢,使用'using'是一个很好的提示......我唯一的问题(以及我试图用类来解决它的原因)是'using'不能依赖于另一个' using'。与'using'需要使用完全限定的类型名称(即,您需要使用'System.Collections.Generic.List'而不是'List')和'using'声明相结合才能真正快速地实现真正的罗嗦。 – Eric 2012-03-05 22:45:11

只因为你的FooList是一个List不会使List成为FooList。

这种方法:

static List<Foo> GetFooList() { 
    return new List<Foo>(); 
} 

...不返回FooList。你的代码实际上是这样的:

FooList list = (FooList) new List<Foo>(); 

这根本不起作用。这是无效的:

string x = (string) new object(); 

你不会期望工作,你会吗?那么为什么你的FooList版本工作?

最接近C#有一个typedef被称为使用别名指令:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace CastTest { 
    using FooList = List<Foo>; 

    class Foo {} 

    class Program { 
     static void Main(string[] args) { 
      FooList list = Program.GetFooList(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() { 
      return new List<Foo>(); 
     } 
    } 
} 

你有什么创造了一个派生类FooList,但是这创造了一个别名FooList。它与List<Foo>没有多少兼容,它List<Foo>

既然你知道一个FooList实际上是List<Foo>的另一个名字,它可能看起来很奇怪。但考虑到FooList本身可能包含成员,编译器不应该允许演员表演变得明显。想象一下你以后在FooList上引入方法(Bar())。 List<Foo>上不存在此方法,如果允许赋值(或强制转换),则类型系统会简单地中断。

因为不是所有的单子都是FooList。例如,我可以有:

public class AnotherFooList : List<Foo> 
{ 
    public object AdditionalPropery {get; set; } 
} 

它也从列表中继承,但不一样的FooList和FooList是不一样的,因为它。

你不能向上转型;但是您可以创建FooList的新实例及其内容

class Foo { } 

    // I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere. 
    class FooList : List<Foo> {} 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      FooList l = new FooList(); 
      l.AddRange(GetFooList().Select(foo => foo)); 

      Console.ReadLine(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() 
     { 
      return new List<Foo>(); 
     } 
    }