2009-08-21 7 views
1
using System; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine(new B("MyName").Name); 
     } 
    } 

    abstract class A 
    { 
     public A(string name) 
     { 
      this.GetType().GetField("Name").SetValue(this, name); 
     } 
    } 

    class B : A 
    { 
     public B(string name) 
      : base(name) 
     { 
     } 

     public string Name 
     { 
      set; 
      get; 
     } 
    } 
} 

Est-il possible de faire quelque chose comme ça?Définition de la valeur d'un champ de la classe dérivée

Répondre

4

Je ne peux pas insister sur le fait que c'est très, très, très mauvais. Vous créez un couplage inverse compliqué, confus et artificiel, manquant cruellement de clarté, manquant de bonnes pratiques et de principes orientés objet, qui va créer un cauchemar de maintenance et de gestion pour les personnes implémentant des dérivées de votre classe abstraite. Faire la bonne chose!!

abstract class A 
{ 
    protected A(string name) 
    { 
     Name = name; 
    } 

    public abstract string Name 
    { 
     get; 
     protected set; 
    } 
} 

class B: A 
{ 
    public B(string name) : base(name) 
    { 
    } 

    private string m_name; 

    public override string Name 
    { 
     get { return "B Name: " + m_name; } 
     protected set 
     { 
      m_name = value; 
     } 
    } 
} 
+0

+1. Vous dites exactement ce que j'ai pensé en lisant la question. Mais je pense toujours que ce n'est pas aussi facile que ça. CA se plaindra parce que vous exécutez du code dans la classe dérivée avant l'initialisation de la classe de base (vous êtes toujours dans le constructeur de A lorsque vous appelez le setter abstrait). Bien sûr, vous pouvez le supprimer tant que vous affectez simplement la valeur au champ. –

+0

@Stefan: Il est vrai qu'il est possible d'avoir un comportement inattendu si vous ne faites pas attention. Je pense que le vrai problème se produit lors de l'implémentation du même scénario dans VB.NET, qui a un ordre de priorité impair. En C#, l'ordre dans lequel les initialiseurs, les constructeurs et les méthodes surchargées sont appelés est au moins logique, et peut être utile s'il est utilisé correctement. Dans VB.NET, c'est un peu étrange et imprévisible, d'où le problème. Mais cela ne se produit que si vous ECRIVEZ le code dans VB.NET. Si vous compilez le code en C# et l'utilisez dans VB.NET, il maintient l'ordre que C# exécute. – jrista

+0

Vous devez faire face au problème dans C#. Lorsque vous implémentez une classe héritée C qui remplace le nom abstrait, vous accédez à l'une des propriétés ou champs de la classe de base dans le setter du nom. Ce champ n'est pas encore initialisé, vous êtes toujours dans le constructeur de la classe de base quand il est appelé. Cela pourrait être une très mauvaise chose, donc l'analyse du code se plaint à ce sujet. –

1

C'est possible, mais je ne le recommanderais pas. Le problème est que votre classe de base en sait beaucoup sur la classe qui en dérive.

Lorsque vous dérivez une classe de votre classe de base abstraite qui ne définit pas la propriété Le nom vous donne une exception à l'exécution.

Si vous prévoyez que chaque classe, qui est dérivée de votre classe de base, possède une propriété Nom, il serait alors plus facile de définir le Nom de dans votre classe de base abstraite et définissez la propriété avec vous constructeur .

1

C'est vraiment une mauvaise forme de le faire. Généralement, vous devriez juste appeler une méthode comme 'SetPossibleData()', et forcer tous les enfants à l'implémenter d'une manière qu'ils décident.

Pourquoi avez-vous besoin de faire cela?

0

Utilisation GetProperty() Méthode,

public A(string name) 
    { 
     this.GetType().GetProperty("Name").SetValue(this,name,null); 
    } 
0

Il serait si chaque classe vraiment hâte droit initialise les champs et les propriétés qu'il définit. Pourquoi B s'attend-il à ce que la classe de base initialise son nom?

abstract class A 
{ 
    public A() 
    { 
    } 
} 

class B : A 
{ 
    // I know, its trivial, but it does the same ... 
    public B(string name) : base() 
    { 
     Name = name; 
    } 

    public string Name { set; get; } 
} 

La seule chose que je pouvais penser pourquoi vous avez écrit ce code est que la classe de base a une certaine logique pour initialiser le champ. L'option directe consiste à laisser la classe dérivée appeler la logique, mais à initialiser la zone elle-même:

abstract class A 
{ 
    public A() 
    { 
    } 

    protected string GenerateName(string someArg) 
    { 
     // complicated logic to generate the name 
    } 

} 

class B : A 
{ 
    public B(string someArg) : base() 
    { 
     Name = base.GenerateName(someArg); 
    } 

    public string Name { set; get; } 
} 
Questions connexes