我想创建一个全局实例并且不知道它是否可能,请以下面的例子为例
我有一个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);
}
这就是我想象会发生的事情:
我认为当我调用构造函数时,我正在销毁第一个引用,这就是为什么最终对象是null
的权利?
我应该在主代码中创建对象,只修改后续表单中的参数吗?
答案 0 :(得分:2)
你实际上并没有创建一个对象。您正在将test
设置为空引用。
您实际上是在对test
的引用传递引用。如果您只想传递引用,请删除ref
关键字。作为引用类型的变量的值已经只是对象的引用。 ref对象不是对象的引用,而是对对象引用的引用。如果您不清楚,请参阅this link。
您正在使用null填充变量cadena
。
3A。 (因为它们是对象并通过引用传递,我猜想Cadena现在有测试地址)
没有。它的值为test
,这是一个空引用。我认为您正在尝试存储对象引用的引用(即指向test
的指针)。实际上,您只存储一个与test
中保存的值相等的指针,在本例中为空。
正确
您的示例中没有代码可以返回并使用有效的引用填充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"方式强>
最好的方式,或者现代最流行的方式,是
例如
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工具包,例如: AutoFac或Unity。这个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();
}
}