2010-03-23 14 views
6

Angenommen, ich habe eine Basisklasse mit dem Namen Visitor und zwei untergeordnete Subscriber und NonSubscriber.Wie ändert man die Klasse eines Objekts dynamisch in C#?

Zunächst ein Besucher aus einem Nicht-Teilnehmer beginnen, das heißt

NonSubscriber mary = new NonSubscriber(); 

Dann später auf dieser „mary“ auf einige Dienste abonniert haben, und ich möchte die Art von „mary“ zu Abonnenten ändern.

Was ist der konventionelle Weg, das zu tun?

Antwort

6

kann das nicht tun. Es tut uns leid. C# ist keine dynamische Sprache.

+4

Sie können jedoch wahrscheinlich das "State" -Muster wie in der GoF beschrieben verwenden. aber Sie müssen den Typ der Klasse/des Objekts nicht ändern! – cruizer

+0

sogar mit einer dynamischen Sprache ÄNDERUNG DER ART EINES OBJEKTS ist nicht immer möglich. – TomTom

+0

Vielen Dank für das Vorschlagen des "State" -Musters ... Ich versuche hier zu tun ist, Unterklasse und Vererbung zu verwenden, so dass jedes Mal, wenn die Seite gerendert wird, eine geeignete abgeleitete Methode aufgerufen wird. Zum Beispiel, für Nicht-Abonnenten möchte ich den Link "Join Now" zeigen. während für Abonnenten ich den Link zu "Today's special" anzeigen möchte, und der Rest der Seite für alle Besucher gemeinsam sind. – Chris

4

Sie müssen eine neue mary = new Subscriber(); erstellen und alle relevanten Eigenschaften kopieren.

Aber ein besserer Ansatz könnte sein, es anders zu modellieren: Geben Sie Visitor eine Liste der Abonnements. Eine leere Liste bedeutet einen Nicht-Abonnenten.

1

Sie können den Typ einer Variablen zur Laufzeit nicht ändern. Sie müssen eine neue Instanz erstellen.

mary = new Subscriber(); 
4

Sie können diese Art der Konvertierung nicht tun. Was sollten Sie ist treat mary als Besucher tun, und wenn die Zeit kommt, eine neue Instanz der „Teilnehmer“ erstellen:

Visitor mary = new NonSubscriber(); 
// Do some Visitor operations 
... 
// Now mary is a Subscriber 
mary = new Subscriber(); 
+0

Genau! Das war es, was ich sagen wollte. :) – albertjan

0

einen Subscriber Konstruktor, der ein NonSubscriber Objekt als Parameter erstellen, oder ein Verfahren erstellen auf dem Objekt NonSubscriber, das eine Subscriber zurückgibt, um zu speichern, dass Sie den Mapping-Code an mehreren Stellen schreiben müssen.

0

Es scheint, als ob Sie Informationen falsch in Ihre Klassenhierarchie codieren. Es wäre sinnvoller, hier ein anderes Muster als Sub-Classing zu verwenden. Zum Beispiel, verwenden Sie nur eine Klasse (Besucher, oder vielleicht könnten Sie es potenziellen Teilnehmer nennen, was auch immer angemessen scheint) und kodieren Sie Informationen über die Dienste, die das Objekt abonniert ist, das dynamisch ändernde Verhalten hinter einem "Strategie" -Muster oder ähnlichem. Es gibt sehr wenig Details in Ihrem Beispiel, aber eine Sache, die Sie in C# tun könnten, ist eine "Abonnenten" -Eigenschaft zu machen, die das Verhalten des Objekts ändern würde, wenn der Status der Eigenschaft geändert würde.

Hier ist ein erfundenes etwas ähnliches Beispiel:

class Price 
{ 
    private int priceInCents; 
    private bool displayCents; 

    private Func<string> displayFunction; 

    public Price(int dollars, int cents) 
    { 
     priceInCents = dollars*100 + cents; 
     DisplayCents = true; 
    } 

    public bool DisplayCents 
    { 
     get { return displayCents; } 
     set 
     { 
      displayCents = value; 
      if (displayCents) 
      { 
       this.displayFunction =() => String.Format("{0}.{1}", priceInCents/100, priceInCents % 100); 
      } 
      else 
      { 
       this.displayFunction =() => (priceInCents/100).ToString(); 
      } 
     } 
    } 

    public string ToString() 
    { 
     return this.displayFunction(); 
    } 
} 
1

Es scheint, dass Sie einige Design-Probleme haben. Ich denke, dass es besser wäre, den Code neu zu gestalten wie:

class Visitor 
{ 
    private bool isSubscriber = false; 

    public bool IsSubscriber 
    { 
     get { return isSubscriber; } 
    } 

    public void Subscribe() 
    { 
     // do some subscribing stuff 
     isSubscriber = true; 
    } 

    public void Unsubscribe() 
    { 
     // do some unsubscribing stuff 
     isSubscriber = false; 
    } 
} 
3

Sie Muster, die die GOF Design Staat oder Strategie ein solches Verhalten zu modellieren verwenden könnte. Mit diesen Mustern scheint es während der Laufzeit so zu sein, als wäre die Klasse der Objekte geändert worden.Denken Sie

0
public class User 
{ 
    public Subscription Subscription { get; set; } 
    public void HandleSubscription() 
    { 
     Subscription.Method(); 
    } 
} 

public abstract class SubscriptionType 
{ 
    public abstract void Method(); 
} 

public class NoSubscription : SubscriptionType 
{ 
    public override void Method() 
    { 
    // Do stuff for non subscribers 
    } 
} 

public class ServiceSubscription : SubscriptionType 
{ 
    public override void Method() 
    { 
    // Do stuff for service subscribers 
    } 
} 

public class Service2Subscription : SubscriptionType 
{ 
    public override void Method() 
    { 
    // Do stuff for service2 subscribers 
    } 
} 

der Code erklärt meine Antwort :)

0

zu den anderen Antworten und Ihren Kommentar hinzufügen, in der Tat Sie den Zustand Muster für Ihre Zwecke verwenden können, wäre es etwas so:

public class MyProgram 
{ 
    public void Run() 
    { 
     Visitor v = new Visitor("Mary"); 

     Debug.Assert(v.SubscriptionLinkText == "Join now"); 

     v.IsSubscribed = true; 
     Debug.Assert(v.SubscriptionLinkText == "Today's special"); 

     v.IsSubscribed = false; 
     Debug.Assert(v.SubscriptionLinkText == "Join now"); 
    } 
} 

public class Visitor 
{ 
    public string Name { get; set; } 

    private bool _isSubscribed; 
    public bool IsSubscribed 
    { 
     get { return this._isSubscribed; } 

     set 
     { 
      if (value != this._isSubscribed) 
      { 
       this._isSubscribed = value; 
       this.OnSubscriptionChanged(); 
      } 
     } 
    } 

    private SubscriptionBase _subscription; 

    public string SubscriptionLinkText 
    { 
     get { return this._subscription.LinkText; } 
    } 

    public Visitor(string name) 
    { 
     this.Name = name; 
     this._isSubscribed = false; 
     this.OnSubscriptionChanged(); 
    } 

    private void OnSubscriptionChanged() 
    { 
     // Consider also defining an event and raising it here 

     this._subscription = 
      SubscriptionBase.GetSubscription(this.IsSubscribed); 
    } 
} 

abstract public class SubscriptionBase 
{ 
    // Factory method to get instance 
    static public SubscriptionBase GetSubscription(bool isSubscribed) 
    { 
     return isSubscribed ? 
       new Subscription() as SubscriptionBase 
       : new NoSubscription() as SubscriptionBase; 
    } 

    abstract public string LinkText { get; } 
} 

public class Subscription : SubscriptionBase 
{ 
    public override string LinkText 
    { 
     get { return "Today's Special"; } 
    } 
} 

public class NoSubscription : SubscriptionBase 
{ 
    public override string LinkText 
    { 
     get { return "Join now"; } 
    } 
} 
Verwandte Themen