2010-03-23 11 views
6

Supongamos que tengo una clase base llamada Visitor, y tiene 2 subclase Subscriber y NonSubscriber.¿Cómo cambiar la clase de un objeto dinámicamente en C#?

Al principio es un visitante a reflexionar a partir de un no suscriptores, es decir

NonSubscriber mary = new NonSubscriber(); 

Luego, más tarde en este "mary" suscrito a algunos servicios, y quiero cambiar el tipo de "María" al suscriptor.

¿Cuál es la forma convencional de hacerlo?

Respuesta

6

no se puede hacer eso. lo siento. C# no es un lenguaje dinámico.

+4

usted, sin embargo, probablemente pueda hacer uso del patrón "Estado" como se describe en el GoF. ¡pero no es necesario cambiar el tipo de clase/objeto! – cruizer

+0

incluso con un idioma dinámico CAMBIAR EL TIPO DE OBJETO no siempre es posible. – TomTom

+0

Muchas gracias por sugerir el patrón "Estado" ... Lo que trato de hacer aquí es hacer uso de la creación de subclases y la herencia de modo que cada vez que se represente la página, se llame a un método derivado apropiado. Por ejemplo, para los no suscriptores, quiero mostrar el enlace "Unirse ahora". mientras que para los suscriptores quiero mostrar el enlace a "Especial de hoy", y el resto de la página es común para todos los visitantes. – Chris

4

Deberá crear una nueva mary = new Subscriber(); y copiar todas las propiedades relevantes.

Pero un mejor enfoque podría ser modelarlo de manera diferente: proporcione Visitor una lista de suscripciones. Una lista vacía significa un No Suscriptor.

1

No puede cambiar el tipo de una variable en tiempo de ejecución. Necesitas crear una nueva instancia.

mary = new Subscriber(); 
4

No puede hacer este tipo de conversión. Lo que debe hacer es mary tratar como visitante, y cuando llega el tiempo, crear una nueva instancia de "abonado":

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

¡Exactamente! esto es lo que iba a decir. :) – albertjan

0

Crear un constructor Subscriber que toma un objeto NonSubscriber como un parámetro, o crear un método en el objeto NonSubscriber que devuelve Subscriber para ahorrarle tener que escribir el código de mapeo en varios lugares.

0

Parece que está codificando información incorrectamente en su jerarquía de clases. Tendría más sentido usar un patrón diferente que la subclase aquí. Por ejemplo, use solo una clase (visitante, o tal vez podría llamarlo potencial suscriptor, lo que parezca apropiado) y codifique información sobre los servicios a los que está suscrito el objeto, moviendo el comportamiento dinámicamente cambiante detrás de un patrón de "Estrategia" o algo similar. Hay muy pocos detalles en su ejemplo, pero una cosa que podría hacer en C# es crear una propiedad de "suscriptor" que cambiaría el comportamiento del objeto cuando se cambiara el estado de la propiedad.

Aquí está un ejemplo un tanto artificiosa relacionados:

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

Parece que usted tiene algunos problemas de diseño. Creo que sería mejor que rediseñar su código como:

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

usted podría utilizar el patrón de diseño GOF estatales o Estrategia para modelar un comportamiento tal. Usando estos patrones, parece que durante el tiempo de ejecución como si la clase de los objetos hubiera sido modificada.

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 
    } 
} 

Piense el código explica mi respuesta :)

0

Agregando a las otras respuestas y su comentario, de hecho, puede utilizar el modelo de estado para su propósito, sería algo parecido a esto:

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"; } 
    } 
} 
Cuestiones relacionadas