【问题标题】:Conversion of Base Class array to Derived Class array基类数组到派生类数组的转换
【发布时间】:2014-04-06 10:39:36
【问题描述】:

是否可以在 C# 中将基类对象数组显式转换为其派生类对象数组之一?我有从 A 类派生的 C 类,我正在尝试将基类对象数组转换为派生类对象数组,但它返回一个空值。

public interface I
{
   public string Name;
   public string Id;
}
public class A
    {
        public string name;
        public string id;
    }

public class B: A,I
{
    public string Name
    {
       get { return name; }
       set{name= value;}
    }

    public string Id
    {
       get { return id; }
       set{id= value;}
    }
}


 A[] baseClassList= GetValues();
 B[] derivedClassList= baseClassList as B[];---THIS IS RETURNING NULL

我该如何解决这个问题?任何帮助表示赞赏。

【问题讨论】:

  • B 在哪里? A 和 B 之间没有关系
  • 现在已修复。对不起。
  • 几个澄清问题,您提到了一个根本不在您的代码中的派生类 C,是拼写错误还是其他什么?您是要转换数组还是转换数组中的每个元素?
  • 对象的底层类型是从GetValues()返回的B类型吗?

标签: c# inheritance casting


【解决方案1】:

你可以很容易地使用 Linq 从 baseClassList 创建一个 B[],但它不会像演员一样简单。

B[] derivedClassList = baseClassList.OfType<B>().ToArray();

编辑:或者 - 如果您想转换数组的 内容,我建议使用复制构造函数。

public B(A source)
{
    Name = source.name;
    Id = source.id;
}

然后你可以像这样转换:

B[] derivedClassList = baseClassList.Select(e => e is B ? (B)e : new B(e)).ToArray();

【讨论】:

  • 这只会获取A[] 中实际上是B 类型的对象,OP 要求提到了转换。
  • @jdphenix - 是的,他们只会获得B 类型的实际对象。但是,OP提到转换 Array 类型,而不是 contents 数组。
  • @jdphenix - 现在涵盖了这两种情况。
【解决方案2】:

为什么不这样做呢?

假设您的baseClassList 集合A 类型的对象都是真正的B 类型的对象。

B[] derivedClassList = baseClassList.Cast<B>().ToArray();

【讨论】:

    【解决方案3】:

    这在本例中不起作用(但无论如何我都会留下答案,以防它对其他人有用)

    var newArray = Array.ConvertAll(array, item => (NewType)item);
    

    (无耻从C# Cast Entire Array?盗取)

    【讨论】:

    • 投反对票的人能否解释一下这个答案的问题?
    • 在 OP 的情况下,您的代码将在运行时抛出 InvalidCastException
    • 啊,真的。我没有足够仔细地阅读示例并假设他知道实例实际上是被强制转换的类型。
    【解决方案4】:

    简单

    string[] names = { "alpha"   , "bravo"  , "charlie" , "delta"    , "echo"   ,
                       "foxtrot" , "golf"   , "hotel"   , "india"    , "juliet" ,
                       "kilo"    , "lima"   , "mike"    , "november" , "oscar"  ,
                       "poppa"   , "quebec" , "romeo"   , "sierra"   , "tango"  ,
                       "uniform" , "victor" , "whisky"  , "x-ray"    , "yankee" ,
                       "zulu"    ,
                     } ;
    A[] As = Enumerable
             .Range(0,names.Length)
             .Select( x => new B{ Id = x.ToString() , Name=names[x] } )
             .Cast<A>()
             .ToArray()
             ;
    B[] Bs = As.Cast<B>().ToArray() ;
    I[] Is = As.Cast<I>().ToArray() ;
    

    【讨论】:

      【解决方案5】:

      我怀疑即使这是可能的。然而,类似的概念以协变和逆变的名义存在于泛型中。详情请看此链接

      http://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx

      您尝试应用的概念是逆变的示例。

      【讨论】:

        【解决方案6】:

        不,您不能这样转换,除非您尝试转换的数组实际上是 B[],它之前被转换为 A[]。

        A[] source = new A[10];
        B[] target = (B[])source; // won't work;
        
        A[] source = new B[10];   // B[] cast to A[], thanks to array covariance
        B[] target = (B[])source; // will work fine
        

        【讨论】:

        • Cast 方法使用显式转换。所以我认为这会抛出InvalidCastException。因为A 不能转换为B
        • @Selman22 如果数组中的项目实际上是B 的实例,在A[] 中,那么这将起作用。如果数组中的项不是B 类型,那么是的,它会失败。
        【解决方案7】:

        这在强制转换的意义上是不可能的,因为A is B 是false。但是,如果您知道它会起作用,那么没有什么能阻止您创建转换方法并使用它。

        我确实必须进行一些更改(您的原始代码无法编译),但这应该会引导您朝着可行的方向前进。

        public interface I {
          string AnotherProperty { get; }
        }
        
        public class A {
          public string Name { get; set; }
          public string Id { get; set; }
        }
        
        public class B : A, I {
          public string AnotherProperty { get; set; }
        }
        
        public static class BExtensions {
          public static B[] FromAArray(this A[] array) {
            var bList = new List<B>();
            foreach (var a in array) {
              bList.Add(new B() { Id = a.Id, Name = a.Name, AnotherProperty = String.Empty });
            }
            return bList.ToArray();
          }
        }
        
        class Program {
        
          static void Main(string[] args) {
            A[] baseClassList = { new A { Name = "Bob", Id = "1" }, new A { Name = "Smith", Id = "2"}};
            B[] derivedClassList = baseClassList.FromAArray();
          }
        }
        

        【讨论】:

        • 这假定数组中的所有项目都是A 类型,而不是B 类型。它们很可能都是 B 类型。
        • @Servy 有没有办法在FromAArray() 中没有丑陋的if (a is B) 来处理这个问题?
        【解决方案8】:

        不使用 Linq 的快速高效解决方案:

        //
        ///<summary>Create an array of a derived class from a list of a base class. Array elements may be null, if the cast was not possible.</summary>
        public static D[] ToArray<T, D>( this IList<T> list ) where D : class {
            if ( !list.IsFilled() ) return null;
            var a = new D[ list.Count ];
            for ( int i = 0; i < list.Count; i++ ) {
                a[ i ] = list[ i ] as D;
            }
            return a;
        }
        

        使用示例:

        return result.ToArray<Member, User>();
        

        【讨论】:

          猜你喜欢
          • 2016-12-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-08
          • 2013-11-17
          • 1970-01-01
          相关资源
          最近更新 更多