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.

4
  • Where is B ? there is no relation between A and B Commented Mar 4, 2014 at 18:12
  • Its fixed now. Sorry. Commented Mar 4, 2014 at 18:16
  • Couple of clarifying questions, you mention a derived class C that is not in your code at all, typo or something else? And are you wanting to convert the array or convert each element in the array? Commented Mar 4, 2014 at 19:00
  • Is the underlying type of the objects being returned from GetValues() of B type? Commented Mar 4, 2014 at 19:51

8 Answers 8

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();
Sign up to request clarification or add additional context in comments.

3 Comments

This will only get objects in the A[] that are actually of type B, the OPs requirements mention conversion.
@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.
@jdphenix - both cases now covered.
5

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

Comments

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

3 Comments

Can the down-voter please explain the problem with this answer?
Your code will throw an InvalidCastException at runtime in the OP's case
Ahh, true. I didn't read the example closely enough and assumed that he knew the instances were actually of the type being cast to.
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() ;

Comments

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.

Comments

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

2 Comments

Cast method uses an explicit cast.So I think that will throw InvalidCastException.Because A cannot be cast to B
@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.
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();
  }
}

2 Comments

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 Is there a way to handle that without an ugly if (a is B) in FromAArray()?
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>();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.