全局对象实例?

时间:2017-01-23 18:27:03

标签: c# class object instance global

我想创建一个全局实例并且不知道它是否可能,请以下面的例子为例

我有一个String_Example类:

namespace Pass_Object_as_Reference_Example
{
    public class String_Example
    {
        public string _str {get;set;}

        public String_Example(string Cadena)
        {
            _str = Cadena;
        }
    }
}

这是我的Form1代码:

public partial class Form1 : Form  
{
    String_Example cadena;

    public Form1(ref String_Example str)
    {
        InitializeComponent();
        cadena = str;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        cadena = new String_Example(textBox1.Text);
        this.Close();
    }
}

这是我的主要代码:

static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            String_Example test = null;

            Form1 frm = new Form1(ref test);
            Application.Run(frm);

            MessageBox.Show(test._str);
        }

这就是我想象会发生的事情:

  1. 创建“test”对象null
  2. 将对象作为对表单
  3. 的引用传递
  4. 表单构造采用“测试”引用并将其分配给对象“cadena”(因为它们是对象并通过引用传递我猜想Cadena现在有测试地址)
  5. 当按下表单1中的按钮时,将调用构造函数并分配文本框字符串,表单已关闭
  6. 使用消息框检查测试对象中的字符串(应该在表单1中指定字符串,但我们只有一个空引用。
  7. 我认为当我调用构造函数时,我正在销毁第一个引用,这就是为什么最终对象是null的权利?

    我应该在主代码中创建对象,只修改后续表单中的参数吗?

2 个答案:

答案 0 :(得分:2)

您的代码正在做什么

  1. 创建"测试" object null
  2. 你实际上并没有创建一个对象。您正在将test设置为空引用。

    1. 将对象作为对表单
    2. 的引用传递

      您实际上是在对test的引用传递引用。如果您只想传递引用,请删除ref关键字。作为引用类型的变量的值已经只是对象的引用。 ref对象不是对象的引用,而是对对象引用的引用。如果您不清楚,请参阅this link

      1. 表单构造采用"测试"引用并将其分配给对象" cadena"
      2. 您正在使用null填充变量cadena

        3A。 (因为它们是对象并通过引用传递,我猜想Cadena现在有测试地址)

        没有。它的值为test,这是一个空引用。我认为您正在尝试存储对象引用的引用(即指向test的指针)。实际上,您只存储一个与test中保存的值相等的指针,在本例中为空。

        1. 当按下表单1中的按钮时,将调用构造函数并分配文本框字符串,表单将被关闭。
        2. 正确

          1. 使用消息框检查测试对象中的字符串(应该在表单1中指定字符串,但我们只有一个空引用。
          2. 您的示例中没有代码可以返回并使用有效的引用填充test

            为什么这永远不会起作用

            如果要将指针传递给变量,则需要根据this article使用非托管代码:

              

            在不安全的上下文中,类型可以是指针类型,值类型或引用类型。指针类型声明采用以下形式之一:

            (强调补充)

            你不能在c#中执行...而在c ++中我也不会这样做,因为无法保证指针会被垃圾收集。这就是托管代码中不允许使用此模式的原因。

            如何做你正在尝试做的事

            我会给你三个选择。可能还有一些(Singleton,ByRef< T>等),但我认为这些是最常见的。

            在程序和表单之间设置父/子

            如果您正在编写一个应用程序,其中有一系列需要访问全局状态的表单,一种常见的模式是使Program本身成为全局状态的容器,并将其作为{{1任何需要它的参数。因此,请按照以下模式重新编写代码:

            parent

            使全局变量成为静态

            或者,如果您不想将指针传递给子对象,则可以创建全局变量public class String_Example { public string _str {get;set;} public String_Example(string Cadena) { _str = Cadena; } } public partial class Form1 : Form { readonly Program _parent; //Reference to class which contains global state. readonly = can only be set in constructor and can never change. public Form1(Program parent) { InitializeComponent(); _parent = parent; } private void button1_Click(object sender, EventArgs e) { _parent.test = new String_Example(textBox1.Text); this.Close(); } } public class Program { public String_Example test; //Notice this is now a member variable static public void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); test = null; Form1 frm = new Form1(this); Application.Run(frm); MessageBox.Show(test._str); } }

            static

            " best"方式

            最好的方式,或者现代最流行的方式,是

            1. 创建一个专门用于包含全局状态的类(或类)
            2. 将状态变量实现为成员变量
            3. 使用像Autofac这样的工厂来获取状态容器的实例
            4. 告诉工厂,无论你多少次打电话,你只想要一个实例
            5. 例如

              public partial class Form1 : Form  
              {
                  public Form1()
                  {
                      InitializeComponent();
                  }
              
                  private void button1_Click(object sender, EventArgs e)
                  {
                      Program.test = new String_Example(textBox1.Text);
                      this.Close();
                  }
              }
              
              public class Program
              {
                  static public String_Example test;  //Notice this is now a static variable, so it can be accessed without a reference to an instance of Program
              
                  static public void Main()
                  {
                      Application.EnableVisualStyles();
                      Application.SetCompatibleTextRenderingDefault(false);
              
                      test = null;
              
                      Form1 frm = new Form1(this);
                      Application.Run(frm);
              
                      MessageBox.Show(test._str);
                  }
              }
              

              您可以自由使用您想要的任何IoC工具包,例如: AutoFacUnity。这个article比较了可用于.NET的主要IoC库。

              这种方法是首选,因为它允许单元测试人员为没有mocking的全局状态提供自己的存根,这通常是设置单元测试最难的部分。

              请注意,在上面的示例中,我正在使用执行代码来引用ProgramGlobals。您还可以使用Dependency Injection设置对象以自动获取引用。很棒的话题,但我的回答已经很长了,所以你可能需要自己研究。

答案 1 :(得分:0)

在不使用global state的情况下实现所需内容的最简单方法是使用类似的类:

public class ByRef<T> 
{
    public T Value
    {
        get;
        set;
    }   
}

然后在Main

var byRef = new ByRef<String_Example>();
Form1 frm = new Form1(byRef);

Form1

public partial class Form1 : Form
{
    ByRef<String_Example> cadena;

    public Form1(ByRef<String_Example> str)
    {
        if (str == null)
            throw new ArgumentNullException("str");

        InitializeComponent();
        cadena = str;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        cadena.Value = new String_Example(textBox1.Text);
        this.Close();
    }
}