C# 全局对象实例?

C# 全局对象实例?,c#,class,object,instance,global,C#,Class,Object,Instance,Global,我想创建一个全局实例,但不知道是否可能,以下面的示例为例 class ProgramGlobals { public String_Example Test {get; set; } } class Program { static void SetupFactory() { var builder = new ContainerBuilder(); builder.RegisterType<ProgramGlobals>()

我想创建一个全局实例,但不知道是否可能,以下面的示例为例

class ProgramGlobals
{
    public String_Example Test {get; set; }
}

class Program
{
    static void SetupFactory()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<ProgramGlobals>().SingleInstance();
    }

    static void Main()
    {
        SetUpFactory();
        var globals = Container.Resolve<ProgramGlobals>();
        globals.Test = null;

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

        MessageBox.Show(globals.Test._str);
    }
}

public partial class Form1: Form
{
    private voide button1_Click(object sender, EventArgs e)
    {
        var globals = Container.Resolve<ProgramGlobals>();
        globals.Test._str = new String_Example(textbox1.Text)
    }
}
我有一个字符串示例类:

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);
        }
这就是我所想象的:

  • 创建“测试”对象空
  • 将对象作为引用传递给窗体
  • 表单构造接受“test”引用并将其分配给对象“cadena”(因为它们是对象并且通过引用传递,我猜cadena现在有了test的地址)
  • 当按下表单1中的按钮时,将调用构造函数并分配文本框字符串,表单将关闭
  • 使用messagebox检查测试对象中的字符串(应该在表单1中分配字符串,但我们只有一个空引用)
  • 我认为当我调用构造函数时,我破坏了第一个引用,这就是为什么最后一个对象是
    null
    对吗

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

    您的代码正在做什么
  • 创建“测试”对象空
  • 实际上,您没有创建对象。您正在将
    test
    设置为空引用

  • 将对象作为引用传递给窗体
  • 实际上,您正在传递对
    test
    的引用的引用。如果您只想传递引用,请删除
    ref
    关键字。作为引用类型的变量的值已经只是对对象的引用。ref对象不是对对象的引用,而是对对象引用的引用。请查看这是否为否你不清楚

  • 表单构造获取“test”引用并将其分配给对象“cadena”
  • 您正在用null填充变量
    cadena

    3a.(因为它们是对象,通过引用传递,我猜Cadena现在有了测试地址)

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

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

  • 使用messagebox检查测试对象中的字符串(应该在表单1中分配字符串,但我们只有一个空引用)
  • 示例中没有返回并使用有效引用填充
    test
    的代码

    为什么这永远行不通 如果要传递指向变量的指针,则需要使用非托管代码,如下所示:

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

    (增加重点)

    <>你不能在C++中做……而且在C++中,我也不会这么做,因为不能保证指针会被垃圾收集。这就是为什么在托管代码中不允许使用这种模式的原因。 如何做你想做的事 我给你三个选择。可能还有一些(Singleton、ByRef等),但我认为这些是最常见的

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

    如果您正在编写一个应用程序,其中有一系列表单需要访问全局状态,那么一个常见的模式是将
    程序本身作为全局状态的容器,并将其作为
    父级
    参数传递给任何需要它的对象。下面是您的代码,遵循此模式:

    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);
        }
    }
    
    使全局变量保持静态

    或者,如果不想将指针传递给子对象,可以将全局变量设置为静态变量:

    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);
        }
    }
    
    最佳方式

    最好的方式,或者说是当今最时髦的方式,就是

  • 创建专门用于包含全局状态的类
  • 将状态变量实现为成员变量
  • 使用类似Autofac的工厂获取状态容器的实例
  • 告诉工厂你只想要一个实例,不管你调用它多少次
  • 比如说

    class ProgramGlobals
    {
        public String_Example Test {get; set; }
    }
    
    class Program
    {
        static void SetupFactory()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<ProgramGlobals>().SingleInstance();
        }
    
        static void Main()
        {
            SetUpFactory();
            var globals = Container.Resolve<ProgramGlobals>();
            globals.Test = null;
    
            Form1 frm = new Form1();
            Application.Run(frm);
    
            MessageBox.Show(globals.Test._str);
        }
    }
    
    public partial class Form1: Form
    {
        private voide button1_Click(object sender, EventArgs e)
        {
            var globals = Container.Resolve<ProgramGlobals>();
            globals.Test._str = new String_Example(textbox1.Text)
        }
    }
    
    类程序全局
    {
    公共字符串_示例测试{get;set;}
    }
    班级计划
    {
    静态无效设置工厂()
    {
    var builder=new ContainerBuilder();
    builder.RegisterType().SingleInstance();
    }
    静态void Main()
    {
    SetUpFactory();
    var globals=Container.Resolve();
    globals.Test=null;
    Form1 frm=新Form1();
    应用程序运行(frm);
    MessageBox.Show(globals.Test.\u str);
    }
    }
    公共部分类Form1:Form
    {
    私有作废按钮1\u单击(对象发送者,事件参数)
    {
    var globals=Container.Resolve();
    globals.Test.\u str=新字符串\u示例(textbox1.Text)
    }
    }
    
    您可以自由使用任何您想要的工具包,例如或。这将比较.NET可用的主要IoC库

    这种方法是首选的,因为它允许单元测试人员为全局状态提供他们自己的存根,而不需要全局状态,这通常是设置单元测试的最困难部分

    请注意,在上面的示例中,我通过执行代码获取对ProgramGlobals的引用。您也可以使用.Great topic设置对象以自动获取引用,但我的答案已经很长了,因此您可能需要自己进行研究。

    您的代码在做什么
  • 创建“测试”对象空
  • 实际上,您没有创建对象。您正在将
    test
    设置为空引用

  • 将对象作为引用传递给窗体
  • 实际上,您正在将引用传递给
    测试的引用。如果您只想传递引用,请删除
    
    
    var byRef = new ByRef<String_Example>();
    Form1 frm = new Form1(byRef);
    
    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();
        }
    }