C # получение деталей из подклассов - PullRequest
1 голос
/ 13 июня 2009

Я полный новичок в C #, так что извините, если это выглядит странно.

У меня есть абстрактный класс, который называется vefHlutir </p> <pre><code>namespace Klasasafn { public abstract class vefHlutur { public abstract List<String> columnNames(); public abstract List<String> toStringList(); } }

// Вот объект, который наследуется от этого абстрактного класса:

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
    }

} 

// А вот код, который я пытаюсь запустить, Item, User и Category все наследуются от 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

Как мне решить эту проблему?

Ответы [ 2 ]

8 голосов
/ 13 июня 2009

Проблема в том, что в 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 в отношении вызова методов, свойств и т. Д. Это должно позволить вашему сценарию работать.

0 голосов
/ 14 июня 2009

Есть способ сделать бросок. Немного небезопасный код! Не бойся этого поста. В основном это тестовый код, чтобы показать, что он работает. Вся работа здесь происходит:

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

    }
  }
}
...