C#从子类获取详细信息

时间:2009-06-13 14:52:59

标签: c# generics inheritance subclass

我是C#的完全新手,请原谅我,如果这看起来很奇怪。

我有一个名为vefHlutir的抽象类

namespace Klasasafn
{
    public abstract class vefHlutur
    {
        public abstract List<String> columnNames();
        public abstract List<String> toStringList();
    }
}

//Here is an object that inherits from this abstract class:

namespace Klasasafn
{
    [Table(Name="Users")]
    public class User: vefHlutur
    {
        public override List<String> columnNames()
        {
            List<String> p = new List<String>();
            p.Add("Nafn");
            p.Add("Email");
            p.Add("Lýsing");
            return p;
        }
        public override List<String> toStringList()
        {
            List<String> p = new List<String>();
            p.Add(name);
            p.Add(email);
            p.Add(descr);
            return p;
        }
    ... more stuff here
    }

} 

//And here is the code I'm trying to run, Item, User and Category all inherit from vefHlutir:

List<Klasasafn.Item> hlutir;
List<Klasasafn.User> notendur;
List<Klasasafn.Category> flokkar;
void Page_Init(object sender, EventArgs e)
{
    hlutir = Fac.getItemList();
    notendur = Fac.getUserList();
    flokkar = Fac.getCategoryList();

    prenta(notendur, Table1);
}

protected void Page_Load(object sender, EventArgs e)
{

}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{

}
protected void Button1_Click(object sender, EventArgs e)
{
    if (DropDownList1.SelectedIndex == 0)
    {
        prenta(notendur, Table1);
    }
    else if (DropDownList1.SelectedIndex == 1)
    {
        prenta(hlutir, Table1);
    }
    else
        prenta(flokkar, Table1);
}
private void prenta(List<vefHlutur> foo, Table f)
{
    List<String> columnNames = foo[0].columnNames();
    TableRow tRow1 = new TableRow();
    f.Rows.Add(tRow1);
    foreach (String i in columnNames)
    {
        TableCell columnNameCell = new TableCell();
        tRow1.Cells.Add(columnNameCell);
        columnNameCell.Controls.Add(new LiteralControl(i));
    }
    foreach (vefHlutur j in foo)
    {
        TableRow tRow = new TableRow();
        f.Rows.Add(tRow);
        List<String> töfluHlutir = j.toStringList();
        foreach (String k in töfluHlutir)
        {
            TableCell tCell1 = new TableCell();
            tRow.Cells.Add(tCell1);
            tCell1.Controls.Add(new LiteralControl(k));
        }
    }
}

namespace Klasasafn { public abstract class vefHlutur { public abstract List<String> columnNames(); public abstract List<String> toStringList(); } }

我的问题是我无法使用prenta方法。

我总是遇到这些错误:

错误1'Forsíða.prenta(System.Collections.Generic.List,System.Web.UI.WebControls.Table)'的最佳重载方法匹配有一些无效的参数

错误2参数'1':无法从'System.Collections.Generic.List'转换为'System.Collections.Generic.List

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:8)

问题是在C#中,当为List<ChildClass>键入方法时,无法使用类型List<ParentClass>。这种类型的转换称为协方差,它在C#中直到4.0才可用,然后仅在接口和事件上可用。

你可以做的是使方法通用并添加约束。

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

此代码正在做的是说prenta将接受List<T>作为任何T为或来自vefHlutur类型的派生的情况的第一个参数。它还允许您将类型T视为关于调用方法,属性等的类型vefHlutur ...这应该允许您的方案工作。

答案 1 :(得分:0)

有一种方法可以进行演员表演。有点不安全的代码!不要害怕这篇文章。它主要是测试代码,以显示它的工作原理。所有工作都在这里进行:

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

}

只要您尝试投射的内容具有与您投射到的内容相同的实例字段布局(继承情况正常),此解决方案就可以正常工作。请注意,有些内容会导致类型不匹配错误:即,如果List尝试在协变情况下创建基类型。只需在完成此操作后进行测试。

我向纯粹主义者道歉,但我是一名康复的c / c ++ vb / aseembly程序员!

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

    }
  }
}