2

我是 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));
        }
    }
}

我的问题是我不能使用 prenta 方法。

我总是收到这些错误:

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

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

我该如何解决这个问题?

4

2 回答 2

9

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

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

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

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

于 2009-06-13T14:59:28.100 回答
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());

    }
  }
}
于 2009-06-13T20:34:33.770 回答