2009-06-13 244 views
1

我是C#的完全新手,所以如果這看起來很奇怪,請原諒。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

如何解決這個問題?

+0

有一種方法可以使它工作。看我的帖子。 – johnnycrash 2009-06-13 20:52:17

回答

8

問題是,在C#中,輸入方法爲List<ParentClass>時,不能使用List<ChildClass>類型。這種類型的轉換稱爲協方差,直到4.0之後纔會在C#中提供,然後僅在接口和事件中提供。

但是你可以做的是使方法通用並添加一個約束。

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

這段代碼做的是說,prenta將接受List<T>作爲其中T是或從類型vefHlutur derivecs任何情況下,第一個參數。它還允許您將T類型視爲與調用方法,屬性等相關的類型vefHlutur。這應該允許您的場景起作用。

+0

非常感謝您的幫助! :) – Haffi112 2009-06-13 17:38:37

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

    } 
    } 
}