views:

670

answers:

2
+8  A: 

The problem is that in C#, the type List<ChildClass> cannot be used when the method is typed for List<ParentClass>. This type of conversion is known as covariance and it will not be available in C# until 4.0 and then only on interfaces and events.

What you can do though is make the method generic and add a constraint.

private void prenta<T>(List<T> foo, Table f)
  where T : vefHlutur
{
  ...
}

What this code is doing is saying that prenta will accept a List<T> as the first parameter for any case where T is or derivecs from the type vefHlutur. It also allows you to treat the type T as if it is the type vefHlutur with respect to calling methods, properties, etc ... This should allow your scenario to work.

JaredPar
Thank you so much, that helped me a lot! :)
Haffi112
A: 

There is a way to do the cast. A little unsafe code! Don't be afraid of this post. Its mostly test code to show that it works. All the work happens here:

static unsafe List<A> CastBasAIL(List<B> bIn) {

  DynamicMethod dynamicMethod = new DynamicMethod("foo1", typeof(List<A>), 
   new[] { typeof(List<B>) }, typeof(void));
  ILGenerator il = dynamicMethod.GetILGenerator();
  il.Emit(OpCodes.Ldarg_0);                     // copy first argument  to stack
  il.Emit(OpCodes.Ret);                         // return the item on the stack
  CCastDelegate HopeThisWorks = (CCastDelegate)dynamicMethod.CreateDelegate(
   typeof(CCastDelegate));

  return HopeThisWorks(bIn);

}

This solution works as long as the thing you are trying to cast has the same instance field layout as the thing you are casting it to (inheritance situations work well). Note, there are some things that will give you type mismatch errors: i.e. if the List attempts to create a base type in a covariant situation. Just test after doing this.

I apologize to purists for this, but I am a recovering c/c++vb/aseembly programmer!

namespace Covariant {

  class A {
    public virtual string Name() { return "A"; }
  }

  class B : A {
    public override string Name() { return "B"; }
  }

  delegate List<A> CCastDelegate(List<B> b);  // be used in the cast

  class Program {

    static unsafe List<A> CastBasAIL(List<B> bIn) {

      DynamicMethod dynamicMethod = new DynamicMethod("foo1", typeof(List<A>), new[] { typeof(List<B>) }, typeof(void));
      ILGenerator il = dynamicMethod.GetILGenerator();
      il.Emit(OpCodes.Ldarg_0);                     // copy first argument  to stack
      il.Emit(OpCodes.Ret);                         // return the item on the stack
      CCastDelegate HopeThisWorks = (CCastDelegate)dynamicMethod.CreateDelegate(typeof(CCastDelegate));

      return HopeThisWorks(bIn);

    }

    static void Main(string[] args) {

      // make a list<B>
      List<B> b = new List<B>();
      b.Add(new B());
      b.Add(new B());

      // set list<A> = the list b using the covariant work around
      List<A> a = CastBasAIL(b);

      // at this point the debugger is miffed with a, but code exectuing methods of a work just fine.
      // It may be that the debugger simply checks that type of the generic argument matches the 
      // signature of the type, or it may be that something is really screwed up.  Nothing ever crashes.

      // prove the cast really worked
      TestA(a);

      return;

    }

    static void TestA(List<A> a) {

      Console.WriteLine("Input type: {0}", typeof(List<A>).ToString());
      Console.WriteLine("Passed in type: {0}\n", a.GetType().ToString());

      // Prove that A is B
      Console.WriteLine("Count = {0}", a.Count);
      Console.WriteLine("Item.Name = {0}", a[0].Name());

      // see if more complicated methods of List<A> still work
      int i = a.FindIndex(delegate(A item) { return item.Name() == "A"; });
      Console.WriteLine("Index of first A in List<A> = {0}", i);
      i = a.FindIndex(delegate(A item) { return item.Name() == "B"; });
      Console.WriteLine("Index of first B in List<A> = {0}\n", i);

      // can we convert a to an array still?
      Console.WriteLine("Iterate through a, after converting a to an array");
      foreach (var x in a.ToArray())
        Console.WriteLine("{0}", x.Name());

    }
  }
}
johnnycrash