views:

133

answers:

4

-edit- Jason makes a good point that i could add both types to a list of A. But i cant use A due to reflections. Thus i want to know a way to convert the base data from one derive to another. I know in C++ in certain cases i could simply do *(A*)this = (A)that. I am hoping there is something just as simple in C#.

I seriously do have the code below, just different names and types.

Since I need to add/create a list i cant use A (objects are expected to be B or C. Also A is abstract). So i just made a List<B> and i am looking for the easiest or 'best' way to do this code wise. I could add a ctor to C that takes in B but i would have to copy paste it to D, E, F if i choose to have them. So that isnt a great way. What is?

I was hoping Convert.ChangeType would work but that was too farfetched and didnt work. What are you suggestion guys?

abstract class A
{
    public int a;
    public SomeClass b;
    public string c;
}

class B : A {}
class C : A {}


List<B> process(int data);
void func()
{
    var b = process(...);
    var cTemp = process(...);
    //now to convert cTemp to C[] or any IEnumerable<C>
}
+4  A: 

There is not going to be a general approach to this problem. Just think of

class Animal { }
class Cat : Animal { }
class Dog : Animal { }

Thinking of inheritance as meaning "is a" the above says that Cat "is a" Animal and Dog "is a" Animal. But that doesn't mean it makes sense to cast or convert a Cat to a Dog or vice versa1. So in general, no dice.

Now maybe there is something specific about your B and C that could help but you haven't given us enough to detail to know.

But the fact that you need to do this says that maybe your design is flawed and should take a step back and look at your problem and see if you are modeling it correctly.

Finally, what's wrong with List<A>? Then you can add both Bs and Cs to the list:

List<A> list = new List<A>();
B b = new B();
C c = new C();
list.Add(b); // okay!
list.Add(c); // okay!

1: Reasoning another way as my son might remind me, dogs go to heaven and cats don't. So, if there were an easy way to convert cats to dogs, cats would have a cheap way to get into heaven. No dice.

Jason
I use reflections and need the type name to be either cat or dog. This is why Animal is abstract, so i dont use the unsupported type. Good answer tho. I was sure i couldnt add dog to a list of animals. -edit- i am going to do an experiment with reflections to see if i can work with the List<A>
acidzombie24
At run-time, the type *will* be either `B` or `C` (provided, there are no other classes derived from `A` here): `List<A> list = ...; A element = list[0]; assert element.GetType() == typeof(A) || element.GetType() == typeof(B)`. Or do you reflect somehow on the type of the generic type parameter to the list? Am I missing something?
Dirk
@acidzombie24: I don't understand what you mean by "But i cant use `A` due to reflections." Can you please elaborate?
Jason
@Dirk: I don't understand your question. I'm sorry. You say "at run-time, the type _will_ be either `B` or `C`." The type of what? Then you say "do you reflect somehow on the type of the generic type parameter to the list?" Why do we need to do that? We know that the list is strongly-typed as `List<A>`. Please clarify.
Jason
@acidzombie24: This was a reaction to the OP's remark that he needed to "use reflection and need the type name to be either cat or dog". As objects have a reference to their "true" class at run-time (obtainable via `GetType()`), this will work even if they are fetched from a collection whose type parameter is some base class/interface. The type dynamic type does not change simply because the object is fetched from a collection declared to hold elements of the base class. Maybe it's me, though, who confuses things here, since I am still not convinced that I understand the OP's question entirely
Dirk
A: 

The best way really is just going to be something like:

List<C> c = new List<C>();
foreach (B item in cTemp)
{
    C temp = new C();
    c.a = item.a;
    c.b = item.b;
    c.c = item.c;
    c.add(temp);
}

That is unless you can change B or C.

NickLarsen
So hand convert it? hmm, i am trying to avoid that.
acidzombie24
@acid: you could use reflection and possbily searlization... but those would just be a different form of hack and maintenance problems
Matthew Whited
A: 

As mentioned in the comments, you can use List(of A) here because it's a common base class for both B and C. But to answer your question more generally, you can "convert" a IEnumerable(Of T1) to another IEnumerable(Of T2) by using either

  1. System.Linq.Enumerable.Cast (as long as T1 can be cast to T2)
  2. System.Linq.Enumerable.Select (you provide the code to convert each element of T1 into an element of T2)
  3. System.Collections.Generic.List(Of T).ConvertAll (again, you provide the function to convert a single T1 to T2 and it gives you back a list of T2)

Example of #3 in C# is below

// ... populate list1
List<PointF> list1 = new List<PointF>();
list1.Add(new PointF(1.0, 1.0));
list1.Add(new PointF(2.0, 2.0));

List<Point> list2 = list1.ConvertAll( pt => new Point((int)pt.X, (int)pt.Y) );
Josh Einstein
sweet i think this is what i wanted. Can it automatically copy the base of one to another? Its time for food. when i get back i am looking up the linq suggested and checking if it works.
acidzombie24
Be very careful here! `Enumerable.Cast` does not use user-defined casts, it only uses reference conversions and boxing/unboxing conversions. Since you can't convert a reference to an instance of `B` to a reference to an instance of `C` (or vice versa) the approach of using `Enumerable.Cast` will fail in general. Note further that these approaches don't solve the problem; you still have to provide a user-defined cast which in general does not make sense.
Jason
I don't think a user defined cast would make sense either. I was speaking generally about how to go from an IEnumerable<T1> to IEnumerable<T2> and in the OP's case #3 is probably the best option other than approaching the problem differently.
Josh Einstein
A: 

I don't find the question entirely clear. I think you are saying that:

  1. You have a List<B> containing instances of B.
  2. You need to convert the instances of B into instances of C (or D or E...).
  3. None of the subclasses of A add any new data members. (Otherwise how would you expect the conversion to work?)
  4. You further need to provide a List<C> (or List<D>...) to some method that specifically requires that type and not a List<A>, either because of its specification or because it does some sort of complicated reflection on the list type.

It's not clear whether all the code involved is under your control or not. If it is, it seems likely the design could be improved to avoid needing to perform these contortions.

Here's a way to convert Bs to Cs or Ds or Es in such a way that you don't need to copy and paste code, but it's very limiting because it requires the subclasses to have parameterless constructors and not to add any fields of their own. I doubt it's the best solution to your problem, but I can't suggest much more without a better idea of what you're doing.

public static T2 WeirdConverter<T1, T2>(T1 item)
    where T1 : A
    where T2 : A, new()
{
    T2 convertedItem = new T2();
    convertedItem.a = item.a;
    convertedItem.b = item.b;
    convertedItem.c = item.c;
    return convertedItem;
}

public static IEnumerable<T2> WeirdSequenceConverter<T1, T2>(IEnumerable<T1> sequence)
    where T1 : A
    where T2 : A, new()
{
    foreach (var item in sequence)
    {
        yield return WeirdConverter<T1, T2>(item);
    }
}

void func()
{
    var b = process(...);
    var cTemp = process(...);
    //now to convert cTemp to C[] or any IEnumerable<C>
    IEnumerable<C> convertedC = WeirdSequenceConverter<B,C>(cTemp);
}

PS - You mention some of your constraints are in some way to do with reflection. I'd recommend not getting carried away with reflection. It's easy to write code that's extremely hard to debug and that is hard to reason about. I'd generally only go for reflection as a last resort, and not as a general problem-solving tool.

Weeble