4

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.

merazuu
  • 4,118
  • 6
  • 18
  • 19

8 Answers8

7

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();
McAden
  • 13,714
  • 5
  • 37
  • 63
  • This will only get objects in the `A[]` that are actually of type `B`, the OPs requirements mention conversion. – jdphenix Mar 04 '14 at 18:52
  • @jdphenix - yes, they will only get objects that are actual of type `B`. However, the OP mentions converting the *Array* type, not the _contents_ of the array. – McAden Mar 04 '14 at 18:57
  • @jdphenix - both cases now covered. – McAden Mar 04 '14 at 19:04
4

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();
Derek W
  • 9,708
  • 5
  • 58
  • 67
1

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?)

Community
  • 1
  • 1
Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76
1

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() ;
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
0

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
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
  • 1
    Cast method uses an explicit cast.So I think that will throw `InvalidCastException`.Because `A` cannot be cast to `B` – Selman Genç Mar 04 '14 at 18:38
  • 1
    @Selman22 If the items in the array are in fact instances of `B`, in an `A[]` then this will work. If the items in the array aren't of type `B`, then yes, it'll fail. – Servy Mar 04 '14 at 18:41
0

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.

Shantanu Gupta
  • 20,688
  • 54
  • 182
  • 286
0

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();
  }
}
jdphenix
  • 15,022
  • 3
  • 41
  • 74
  • This assumes that all of the items in the array are of type `A`, and not of type `B`. They could very well all be of type `B`. – Servy Mar 04 '14 at 18:43
  • @Servy Is there a way to handle that without an ugly `if (a is B)` in `FromAArray()`? – jdphenix Mar 04 '14 at 18:50
0

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>();
cskwg
  • 790
  • 6
  • 13