为什么这个C#转换示例不起作用?

时间:2012-03-05 22:24:46

标签: c# .net casting

我试图理解为什么这个演员不起作用:

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:无法将类型为'System.Collections.Generic.List`1 [CastTest.Foo]'的对象强制转换为'CastTest.FooList'。

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

7 个答案:

答案 0 :(得分:7)

仅仅因为您的FooList是List而不会使List成为FooList。

答案 1 :(得分:5)

您无法自动从父类强制转换为派生类:只是因为您尝试投射的对象是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>;

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

答案 2 :(得分:4)

此方法:

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

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

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

这根本不起作用。它无效:

string x = (string) new object();

你不会指望这样,你呢?那你的FooList版本为什么会起作用?

答案 3 :(得分:2)

最接近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>

答案 4 :(得分:2)

因为并非所有List都是FooList。例如,我可以:

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

它也继承自List,但与FooList不同,FooList与它不同。

答案 5 :(得分:1)

由于您知道FooList实际上只是List<Foo>的另一个名称,因此它可能看起来很奇怪。但鉴于FooList可能包含成员本身,编译器不应允许强制转换变得明确。想象一下,您稍后会在Bar()上介绍一种方法(FooList)。 List<Foo>上不存在此方法,如果允许赋值(或强制转换),则类型系统将会中断。

答案 6 :(得分:1)

你不能上升;但你可以创建一个新的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>();
        }
    }