从另一个类更改私有字符串

时间:2012-12-18 15:02:16

标签: c# forms inheritance properties private

我想知道为什么我的Events类中的私有变量'name'在我从我继承自Events的Leisure类访问属性时不会改变。我需要使用Leisure来改变它,然后在我的表单类中,它应该能够从事件中读取'name'的值。见下文:

public partial class Form1 : Form //Main form class
{
    private string eventType; //used for event type selection
    private string formEventName; //used to store selected event name


     private void itemSend_Click(object sender, EventArgs e)
    {
        //encapsulation
        Events myEv = new Events();
        string name=itemInput.Text; 
        myEv.myEvent(eventType, name);
        formEventName = myEv.myName;
        txtOutput.Text = "Event name is " + formEventName + "\r\n";            
    }

class Events:Form1
{
    private string name; //private variable for event name      
     public string myName //used to change property value depending on what eveny type/ event name
    {
        get { return name; }
        set { name = value; }   
    }
    public void myEvent(string eventType, string eventName) //variable recieved from main form class
    {
        if (eventType == "Leisure")
        {

           Leisure myLes = new Leisure(); 
           myLes.eventNames(eventName);  

        }
        else
        {
            //test for other event types
        }  
    }

    class Leisure:Events
 {
    public void eventNames(string eventName) 
    {

        //when adding new items add one with a capital and one without
        myEventNames.Add("music");
        myEventNames.Add("Music");
        if (myEventNames.Contains(eventName))
        {
            myName = eventName;
        }
        else
        {
            MessageBox.Show("item not found, please try again"); //error message
        }
    }
  }

4 个答案:

答案 0 :(得分:2)

您正在使用的myName属性会更改myLes实例的name私有字段,而不会更改在ItemSend_Click中创建的myEv实例的名称私有字段。

在创建类的实例时,在面向对象语言中,该实例具有在类中声明的每个非静态私有/公共变量的副本。所以当你写

   Leisure myLes = new Leisure(); 

您正在创建一个Leisure类的实例,但是这个实例在从Events继承时有一组不同的内部变量,而不是当前Event实例(myEv)的相同变量。

查看您的代码我建议创建一个名为

的第三个类
public class EventFactory
{
    public Event CreateEvent(string eventType, string eventName)
    {
        switch(enventType)
        {
            case "Leisure":
                 Leisure myLes = new Leisure(); 
                 myLes.eventNames(eventName);  
                 return myLes;
            // case Add other specialized events here:
            // break;
            default:
                 return null;
        }
    }
}

更改您的Events类,从Form1中删除继承(据我所知,不需要)和方法myEvent

现在你的ItemSend_Click可以用这种方式编写

private void itemSend_Click(object sender, EventArgs e)
{
    Events myEv = new EventFactory().CreateEvent(eventType, itemInput.Text);
    formEventName = myEv.myName;
    txtOutput.Text = "Event name is " + formEventName + "\r\n";            
}

这是有效的,因为Leisure派生自Events,您可以将每个Leisure实例视为事件实例。

答案 1 :(得分:2)

Events继承Form1似乎是错误的。

当您说new Events()时,您会得到一个与现有表单无关的新对象,您对其所做的任何更改都不会影响现有表单。当你说new Leisure()时会再次发生这种情况。

答案 2 :(得分:1)

您只需更改myName字段中myLes (Leisure)变量的myEv,这就是为什么myEv.myName仍为空。

答案 3 :(得分:0)

因此,您遇到的问题只是代码中主要基本问题的一个小症状,只会在您继续时继续显示。

我已经将你所拥有的东西重新编写成更符合你传统上看到的东西的东西。它并不完美,我试图让事情变得相当简单,以免马上对你施加过多的伤害。

public partial class Form1 : Form //Main form class
{
    private TextBox itemInput;
    private TextBox txtOutput;
    private string eventType; //used for event type selection
    private string formEventName; //used to store selected event name

    private void itemSend_Click(object sender, EventArgs e)
    {
        string name = itemInput.Text;
        try
        {
            Event myEvent = Event.Create(eventType, name);
            txtOutput.Text = "Event name is " + myEvent.Name + "\r\n";
        }
        catch (ArgumentException ex)//if the event name isn't valid
        {
            MessageBox.Show(ex.Message);
        }
    }
}

public abstract class Event
{
    public string Name { get; private set; }
    public Event(string eventName)
    {
        Name = eventName;
    }
    public static Event Create(string eventType, string eventName)
    {
        if (eventType == "Leisure")
        {

            Leisure myLes = new Leisure(eventName);
            return myLes;

        }
        //  else if { ... } test for other event types
        else
        {
            return null;
        }
    }
}

public class Leisure : Event
{
    private static List<string> myEventNames =
        new List<string>() { "music", "Music" };
    public Leisure(string eventName)
        : base(eventName)
    {
        if (!myEventNames.Contains(eventName))
        {
            throw new ArgumentException("Not a valid Leisure event name");
        }
    }
}

所以,让我们回顾一些变化。首先,Event不会从Form1继承。它不应该这样做。事件在概念上根本不是一种形式,更不用说特定类型的形式了。 Event不应该以任何方式知道任何形式,不仅仅是继承。它只是Form1将使用的其他类,但它可以很容易地被任何其他类型的类,形式或其他类型使用。

除了让Event不从Form继承之外,我还把它作为摘要。它没有任何抽象方法,只是你不应该只创建一个普通的Event,你应该只创建一些特定类型的事件。作为一个共同的基类,最简单的方法是防止意外创建,并通过abstract来提高可读性。

我也让Event不可变。而不是允许在任何时候更改名称,创建事件而不给它命名,然后在以后更改它,我已经配置它,以便您需要在创建事件之前提供名称和类型,然后没有办法一旦它被创建就改变它。 Name在构造函数中设置,我添加了一个静态Create方法,逻辑可用于选择Event的正确子类型并实际创建它。这是“工厂模式”的简单版本。请注意,通常我不会将类型作为字符串传递。我会把它变成Enum,这样就可以更容易地判断出有效选项是什么。

现在转到Leisure。从逻辑上讲,Leisure确实是Event并且应该从中继承。您的问题源于您创建了Event的实例,以及Leisure的实例,并假设它们共享相同的变量。他们没有,但是由于你不能拥有Event的实例,这种混乱应该消失。

创建Leisure时,它使用基类构造函数来设置Name,因为它无权设置属性本身。

从我所看到的myEventNames只是一个有效名称列表,它似乎在不同类型的Leisure个实例之间没有变化,所以它有意义static 1}},这意味着它在所有实例之间共享,并且只创建一次。

我还将MessageBox调用移出Leisure类型的构造函数。相反,我正在抛出异常。这里的主要想法是你不应该将你的UI代码与业务代码混合在一起。 EventLeisure都是业务对象,不应该知道UI存在的内容(如果有的话)。你应该可以从控制台应用程序,ASP应用程序等使用它们。最重要的是,我们试图说的是这是一个无效的名称,类型不应该存在,最终的结果是在构造函数中抛出一个Excpetion是对象永远不会变为“有效”。我们不允许创建一个不存在的对象,而不允许它们继续使用该对象。

try/catch中的Form1阻止了该异常,根据创建事件的失败,它会显示相应的MessageBox