【问题标题】:Why doesn't this C# casting example work?为什么这个 C# 转换示例不起作用?
【发布时间】:2012-03-05 22:24:46
【问题描述】:

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

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”类型。

谁能解释为什么这不起作用,以及我是否能以某种方式解决这个问题?

【问题讨论】:

  • 哪一行产生了错误?
  • 哪种说法正确:FooList 是 List,还是 List 是 FooList?
  • 如果你不喜欢额外的类型,使用隐式类型变量。像这样:var list = Program.GetFooList();
  • 到处写List&lt;Foo&gt;有什么大问题?我曾经使用过一个强类型列表的代码库,这让我很痛苦。
  • @eouw0o83hf,在任何地方都写 List 并不是什么问题,但我只是想出了一个人为的例子来说明问题。我真的在尝试输入更长的类型名(如列表字典)

标签: c# .net casting


【解决方案1】:

仅仅因为你的 FooList 是一个 List 并不能使 List 成为一个 FooList。

【讨论】:

    【解决方案2】:

    您不能自动从父类转换为派生类:仅仅因为您尝试转换的对象是 List&lt;Foo&gt; 并不一定使其成为 FooList

    退房:

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

    您可以编写一个将List&lt;Foo&gt; 转换为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>;
    

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

    【讨论】:

    • 谢谢,使用using 是一个很好的提示......我唯一的问题(以及我试图使用类来解决它的原因)是一个using 不能依赖在另一个 using 中定义的类型上。再加上using 需要使用完全限定的类型名(即,您需要使用System.Collections.Generic.List 而不是List)和using 声明会变得非常罗嗦。
    【解决方案3】:

    这个方法:

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

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

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

    这根本行不通。它与以下内容一样无效:

    string x = (string) new object();
    

    你不会指望它会起作用,对吗?那么为什么你的FooList 版本会起作用呢?

    【讨论】:

      【解决方案4】:

      与 typedef 最接近的 C# 称为 using alias 指令:

      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&lt;Foo&gt; 有点不兼容,它 List&lt;Foo&gt;

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

          既然您知道FooList 实际上只是List&lt;Foo&gt; 的另一个名称,它可能看起来很奇怪。但是考虑到 FooList 可以包含成员本身,编译器显然不应该允许强制转换。想象一下,您稍后在FooList 上介绍一个方法(Bar())。 List&lt;Foo&gt; 上不存在此方法,如果允许分配(或强制转换),类型系统将简单地中断。

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-04-10
              • 1970-01-01
              • 2021-12-20
              • 2018-06-12
              • 2014-06-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多