2009-06-13 8 views
1

Je suis un débutant complet à C# alors excusez-moi si cela semble étrange.C# obtenir des détails de sous-classes

J'ai une classe abstraite appelée 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)); 
     } 
    } 
} 

Mon problème est que je ne peux pas utiliser la méthode Prenta.

J'obtiens toujours ces erreurs:

erreur 1 Le match de la meilleure méthode surchargée pour 'Forsíða.prenta (System.Collections.Generic.List, System.Web.UI.WebControls.Table)' a des arguments invalides

erreur 2 Argument '1': ne peut pas convertir 'System.Collections.Generic.List' à « System.Collections.Generic.List

Comment puis-je résoudre ce problème?

+0

Il existe un moyen de le faire fonctionner. Voir mon message. – johnnycrash

Répondre

8

Le problème est qu'en C#, le type List<ChildClass> ne peut pas être utilisé lorsque la méthode est tapée pour List<ParentClass>. Ce type de conversion est connu sous le nom de covariance et il ne sera pas disponible en C# jusqu'à 4.0 et seulement sur les interfaces et les événements.

Ce que vous pouvez faire est de rendre la méthode générique et d'ajouter une contrainte.

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

Qu'est-ce que ce code fait dit que Prenta acceptera un List<T> comme premier paramètre pour tous les cas où T est ou derivecs de type vefHlutur. Il vous permet également de traiter le type T comme s'il s'agissait du type vefHlutur en ce qui concerne les méthodes d'appel, les propriétés, etc. Cela devrait permettre à votre scénario de fonctionner.

+0

Merci beaucoup, ça m'a beaucoup aidé! :) – Haffi112

0

Il existe un moyen de réaliser cette conversion. Un petit code dangereux! N'ayez pas peur de ce post. Son code de test principalement pour montrer que cela fonctionne. Tout le travail se passe ici:

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

} 

Cette solution fonctionne aussi longtemps que la chose que vous essayez de jeter a la même disposition de champ d'instance comme la chose que vous le jeter à (situations d'héritage bien). Notez qu'il y a certaines choses qui vous donneront des erreurs d'incompatibilité de type: c'est-à-dire si la liste tente de créer un type de base dans une situation covariante. Juste tester après avoir fait ça. Je m'excuse auprès des puristes pour cela, mais je suis un programmeur récupérateur 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()); 

    } 
    } 
} 
Questions connexes