2010-02-25 8 views
2

Je veux construire une entité forme, qui doit contenir les champs de formulaire formulaireListe générique des différents types de C#

donc: je veux avoir une classe qui ressemble à quelque chose comme ceci:

public abstract class form { 
public string FormName; 
public IList<FormField> Fields; 
} 

i voulez que ma classe FormField ait une méthode: getValue.

Mais, je veux que ce soit générique, donc getValue ne retournerait pas un objet, mais la valeur réelle de l'objet ..

+2

Plutôt que de discuter de ce que vous voulez que la signature de GetValue à ressembler, nous dire comment vous voulez écrire le consommateur de la liste des champs qui appelle GetValue. Pouvez-vous expliquer comment cette chose va être utilisée, parce que je ne comprends pas ce que vous voulez ici. –

+1

La convention .Net est pour les noms de classe PascalCase, c'est-à-dire que chaque "mot" dans le nom d'une classe commence par une majuscule. Dans votre cas, remplace 'form' par' Form'. Vous pouvez voir la convention comme 'IList' et' FormField' sont PascalCased. 'String',' Int32' et d'autres types de base ont tous un équivalent minuscule, par exemple. 'string' et' int', mais c'est spécifique à C# et non exposé à l'extérieur. – Dykam

+0

Je ne sais pas si c'est un doublon, mais cela serait-il utile pour vous: http://stackoverflow.com/questions/1848312/how-can-i-store-different-objects-in-a-single-list – Juliet

Répondre

3

Malheureusement, il n'y a aucun moyen de créer une seule liste générique contenant des objets, qui ont chacun un type de retour différent pour une méthode donnée, comme celle que vous voulez. Le mieux que vous pouvez faire est une interface, ou une classe de base, et une méthode qui renvoie Object.

Cela signifie que vous devrez lancer, mais alors, vous devriez le faire de toute façon.

Comment cela fonctionnerait de code si vous pourriez avoir différents types de retour:

FormField f = _Fields[0]; 
?? x = f.GetValue(); 
+0

hmmm, Je pense que votre droite, je pensais quelque chose dans le sens de la var, mais de ce que je comprends c'est juste un sucre syntaxique dans C# – MindFold

+0

Correct, "var" n'est pas dynamique, vous pourriez être en mesure de le faire avec le mot-clé dynamique (au moins du point de vue "var"), mais vous ne pourriez toujours pas avoir des types de retour différents. Je prendrais votre code deux pas en arrière et essayerais de voir s'il y a une manière différente d'accomplir vos buts. –

+0

Existe-t-il un autre bon moyen d'implémenter cela, alors vous dites que je dois abandonner la vérification de type explicite? – MindFold

1

public abstract class Form<T>{ 
    public string FormName; 
    public IList<FormField<T>> Fields; 
} 

public class FormField<T>{ 
    public T getValue { ... code here ... } 
} 
+0

Cela signifie que mon formulaire contiendra seulement, par exemple des champs de chaîne, mais ce n'est pas ce que je veux, je veux pouvoir contenir plusieurs types de champs différents. – MindFold

+0

@MindFold: J'ai modifié cette solution en utilisant une interface pour accomplir ce que vous cherchez. – recursive

2

Cela fonctionne:

public abstract class Form<T>{ 
    public string FormName; 
    public IList<IFormField> Fields; 
} 

public class FormField<T> : IFormField{ 
    public T getValue() { return default(T); } 

    object IFormField.getValue() { 
     return this.getValue(); 
    } 
} 

public interface IFormField { 
     object getValue(); 
} 
+0

Cela fonctionnera, mais encore une fois, cela ne garantira pas que j'aurai la méthode GetValue sur chaque élément de la liste, c'est plus une solution de contournement qu'une solution. – MindFold

+0

@MindFold: J'ai ajouté une méthode getValue à l'interface qui devrait résoudre ce problème. – recursive

+0

mmm, comment ça va fonctionner? me rendra-t-il un objet ou le T? – MindFold

1
public abstract class Form { 
    public IList<FormField> Fields; 
    public string FormName; 
} 

public class FormField { 
    private Object field; 

    public T getValue<T>() { 
     return (T) field; 
    } 
} 
1

S'il vous plaît voir le code complet ci-dessous. fonctionne Ma solution comme:

var myForm = new Form(); 
var int_value = myForm.Fields 
      .OfType<IntegerFormField>() 
      .First(c => c.Name == "c1").GetValue(); 
var decimal_value = myForm.Fields 
      .OfType<DecimalFormField>() 
      .First(c => c.Name == "c2").GetValue(); 

Les interfaces de terrain:

public interface IFormField 
    { 
     object GetValue(); 
     string Name { get; } 
    } 

    public interface IFormField<T> : IFormField 
    { 
     T GetValue(); 

    } 

La classe de base abstraite pour tous les champs de formulaire:

abstract class FormFieldBase<T> : IFormField<T> 
     { 
      private readonly T _value; 

      public FormFieldBase(T value, string name) 
      { 
       _value = value; 
       Name = name; 
      } 

      #region IFormField<T> Members 

      public virtual T GetValue() 
      { 
       return _value; 
      } 

      #endregion 

      #region IFormField Members 

      object IFormField.GetValue() 
      { 
       return _value; 
      } 

      public string Name { get; private set; } 

      #endregion 
     } 

mise en œuvre du champ de formulaire Deux exemple:

class IntegerFormField : FormFieldBase<int> 
{ 
    public IntegerFormField(int value, string name) : base(value, name) { } 
} 

class DecimalFormField : FormFieldBase<decimal> 
{ 
    public DecimalFormField(Decimal value, string name) : base(value, name) { } 
} 

La classe de formulaire:

class Form 
    { 
     public IList<IFormField> Fields 
     { 
      get 
      { 
       return new List<IFormField>(){ 
         new IntegerFormField(10, "c1"), 
new DecimalFormField(200, "c2") 
       }; 
      } 
     } 
    } 

HTH

Questions connexes