Question

Is it possible in C# to explicitly convert a base class object array to one of it's derived class object array? I have class C derived from class A and I'm trying to convert the base class object array to the derived class object array but it returns returns a null value.

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

How can i solve this? Any help is appreciated.

Was it helpful?

Solution

You can create a B[] from baseClassList using Linq pretty easily but it won't be as simple as a cast.

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

EDIT: Alternatively - if you want to convert the contents of the array I'd recommend a copy-constructor.

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

Then you can convert like so:

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

OTHER TIPS

Why not just do this?

Assuming that your baseClassList collection of objects of A type are all really objects of B type underneath.

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

THIS WILL NOT WORK IN THIS EXAMPLE (but I'm leaving the answer up anyway in case it is useful to others)

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

(shamelessly stolen from C# Cast Entire Array?)

Easy as

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() ;

I doubt even if this is possible. However similar concept exists in Generics by the name of covariance and contravariance. Please see this link for details

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

Concept that you are trying to apply is an example of contravariance.

No, you can't convert it like that, unless the array you're trying to convert is actually B[] which was cast to A[] before.

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

This is not possible in the sense of casting, because A is B is false. However, if you know it will work, nothing stops you from creating a conversion method and using it.

I did have to make a couple of changes (your original code doesn't compile), but this should steer you in a direction that will work.

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();
  }
}

Fast and efficient solution without using 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;
}

Usage sample:

return result.ToArray<Member, User>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top