How to change the class of an object dynamically in C#?

后端 未结 10 1282
囚心锁ツ
囚心锁ツ 2021-01-05 17:09

Suppose I have a base class named Visitor, and it has 2 subclass Subscriber and NonSubscriber.

At first a visitor is start off from a NonSubscriber, i.e.

<         


        
相关标签:
10条回答
  • 2021-01-05 17:47

    can't do that. sorry. C# is not a dynamic language.

    0 讨论(0)
  • 2021-01-05 17:53

    You will have to create a new mary = new Subscriber(); and copy all relevant properties.

    But a better approach might be to model it differently: Give Visitor a list of subscriptions. An empty list means a NonSubscriber.

    0 讨论(0)
  • 2021-01-05 17:54

    It seems like you are encoding information incorrectly into your class hierarchy. It would make more sense to use a different pattern than sub classing here. For example, use only one class (visitor, or perhaps you could name it potential subscriber, whatever seems appropriate) and encode information on the services the object is subscribed to, moving the dynamically changing behavior behind a "Strategy" pattern or some such. There's very little detail in your example, but one thing you could do in C# is to make a "subscriber" property which would change the behavior of the object when the state of the property was changed.

    Here's a contrived somewhat related example:

    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();  
        }
    }
    
    0 讨论(0)
  • 2021-01-05 17:57

    Adding to the other answers and your comment, you indeed can use the state pattern for your purpose, it would go something like this:

    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"; }
        }
    }
    
    0 讨论(0)
  • 2021-01-05 18:01

    You cant do this type of conversion. What you should do is treat mary as a visitor, and when time arrives, create a new instance of "subscriber":

    Visitor mary = new NonSubscriber();
    // Do some Visitor operations
    ...
    // Now mary is a Subscriber
    mary = new Subscriber();
    
    0 讨论(0)
  • 2021-01-05 18:01
    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
      }
    }
    

    Think the code explains my answer :)

    0 讨论(0)
提交回复
热议问题