如何在C#中动态更改对象的类?

时间:2010-03-23 08:53:13

标签: c#

假设我有一个名为Visitor的基类,它有2个子类Subscriber和NonSubscriber。

首先,访客是从NonSubscriber开始的,即

NonSubscriber mary = new NonSubscriber();

后来这个“mary”订阅了一些服务,我想把“mary”的类型改为Subscriber。

这样做的常规方法是什么?

10 个答案:

答案 0 :(得分:6)

不能那样做。抱歉。 C#不是动态语言。

答案 1 :(得分:4)

您必须创建新的mary = new Subscriber();并复制所有相关属性。

但更好的方法可能是对其进行不同的建模:给Visitor订阅列表。空列表表示NonSubscriber。

答案 2 :(得分:4)

您无法进行此类转换。 您应该做的是将玛丽视为访客,当时间到来时,创建一个新的“订阅者”实例:

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

答案 3 :(得分:3)

您可以使用GOF设计模式 State 策略来模拟此类行为。使用这些模式,在运行时似乎已经更改了对象的类。

答案 4 :(得分:1)

您无法在运行时更改变量的类型。您需要创建一个新实例。

mary = new Subscriber();

答案 5 :(得分:1)

您似乎遇到了一些设计问题。我认为重新设计代码会更好:

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

答案 6 :(得分:0)

创建一个Subscriber构造函数,将NonSubscriber对象作为参数,或者在NonSubscriber对象上创建一个返回Subscriber的方法,以节省您的编写多个地方的mappping代码。

答案 7 :(得分:0)

您似乎错误地将信息编码到类层次结构中。在这里使用不同于分类的模式会更有意义。例如,仅使用一个类(访问者,或者您可能将其命名为潜在订阅者,无论什么似乎合适)并对关于该对象所订阅的服务的信息进行编码,将动态变化的行为移动到“策略”模式或其他类似的背后。您的示例中的细节很少,但您可以在C#中执行的一项操作是创建一个“订阅者”属性,该属性会在更改属性状态时更改对象的行为。

这是一个人为的相关例子:

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();  
    }
}

答案 8 :(得分: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
  }
}

认为代码解释了我的答案:)

答案 9 :(得分:0)

添加其他答案和评论,你确实可以将状态模式用于你的目的,它会是这样的:

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