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.prenta(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>。このタイプの変換は共分散と呼ばれ、C# では 4.0 までは使用できず、その後はインターフェイスとイベントでのみ使用できます。

ただし、できることは、メソッドをジェネリックにして、制約を追加することです。

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

このコードが行っていることはList<T>、T が vefHlutur 型である場合、または T から派生している場合、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);

}

このソリューションは、キャストしようとしているものが、キャスト先のものと同じインスタンス フィールド レイアウトを持っている限り機能します (継承の状況はうまく機能します)。型の不一致エラーが発生する場合があることに注意してください。つまり、リストが共変の状況で基本型を作成しようとした場合などです。これを行った後、テストするだけです。

純粋主義者には申し訳ありませんが、私は回復中の 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 に答える