C# - Winforms - 全局变量

37

我希望在整个项目中都可以访问一些全局变量,不管在哪个表单中都能够使用。我该怎么做?

8个回答

91

你可以使用静态类来实现这个目的。 像这样:

static class Global
{
    private static string _globalVar = "";

    public static string GlobalVar
    {
        get { return _globalVar; }
        set { _globalVar = value; }
    }
}

并且在任何你可以编写的地方使用:

GlobalClass.GlobalVar = "any string value"

9
通过属性公开值可以得到+1,这样就有可能在需要时添加锁定机制,而不改变已存在的代码访问该值的方式。 - Fredrik Mörk
1
非常感谢 - 我只有一个问题:是否可能将另一个窗体上的标签文本“数据绑定”到此静态类的属性? - CeOnSql

18

在这里达成共识的是将全局变量作为静态成员放入静态类中。当您创建一个新的Windows Forms应用程序时,它通常会带有一个Program类(Program.cs),它是一个静态类,并且作为应用程序的主入口点。它在整个应用程序的生命周期内存在,因此我认为最好将全局变量放在那里,而不是创建一个新的类。

static class Program
{
    public static string globalString = "This is a global string.";

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

并像这样使用:

public partial class Form1 : Form
{
    public Form1()
    {
        Program.globalString = "Accessible in Form1.";

        InitializeComponent();
    }
}

正是我所需要的。简单易用,为我节省了很多时间和烦恼,哈哈。谢谢。 - Errol Chaves Moya

6

或者您可以将全局变量放在app.config中。


1
我已经开始将我的app.config封装在一个静态类中,以便可以强类型访问设置。这样,我认为我既具备了可配置性又具备了强类型特性。 - MPritchard

5

一种方法是,

在解决方案资源管理器中找到您的项目,然后进入“属性”>“设置”>“Settings.Settings”。单击此文件并从IDE中定义您的设置。

通过以下方式访问它们:

Properties.Settings.Default.MySetting = "hello world";

5

2
如果您正在使用Visual C#,您只需要在Program.cs中添加一个继承Form的类,并在每个Form*.cs中将所有继承自Form的类更改为您的类。
//Program.cs
public class Forms : Form
{
    //Declare your global valuables here.
}

//Form1.cs
public partial class Form1 : Forms    //Change from Form to Forms
{
    //...
}

当然,可能有一种方法可以在不修改Form类的情况下扩展它。如果是这样的话,你只需要继承它!由于所有的表单都默认继承它,因此在其中声明的所有变量将自动成为全局变量!祝好运!!!

很棒的答案。如果我们还使用DI,它允许真正的继承。 - James

2
public static class MyGlobals
{
  public static string Global1 = "Hello";
  public static string Global2 = "World";
}

public class Foo
{

    private void Method1()
    {
       string example = MyGlobals.Global1;
       //etc
    }
}

1
他们已经回答了如何使用全局变量。
我将告诉你为什么使用全局变量是一个坏主意,这是由question在西班牙的stackoverflow上进行的调查所得出的结果。
更改的影响
全局变量的问题在于它们创建了隐藏的依赖关系。当涉及到大型应用程序时,您自己不知道/记得/清楚您拥有的对象及其关系。
因此,您无法清楚地了解全局变量正在使用多少个对象。如果您想要更改全局变量的某些内容,例如每个可能值的含义或其类型,那么这将影响多少个类或编译单元?如果受影响的数量很小,那么进行更改可能是值得的。如果影响很大,则可能值得寻找其他解决方案。
但影响是什么呢?因为全局变量可以在代码中的任何地方使用,所以很难衡量它的影响。
此外,始终尽量使用生命周期最短的变量,这样使用该变量的代码量就尽可能少,从而更好地理解其目的和修改者。全局变量在程序运行期间都存在,因此任何人都可以使用该变量,无论是读取还是更改其值,都会使得很难知道该变量在任何给定的程序点上将具有什么值。
销毁顺序是另一个问题。变量总是按它们创建的相反顺序被销毁,无论它们是本地变量还是全局/静态变量(一个例外是原始类型,如intenum等,如果它们是全局/静态的,直到结束程序它们才不会被销毁)。问题在于很难知道全局(或静态)变量的构建顺序。原则上,这是不确定的。如果所有的全局/静态变量都在一个编译单元中(也就是说,你只有一个.cpp),那么构建顺序就与书写顺序相同(即,在之前定义的变量先构建)。
但是,如果你有多个带有自己全局/静态变量的.cpp文件,全局构造顺序是不确定的。当然,每个编译单元(每个.cpp)中的顺序是被尊重的:如果全局变量AB之前定义,A将在B之前创建,但是其他.cpp的变量可能在AB之间初始化。例如,如果你有三个具有以下全局/静态变量的单元:

Image1

在可执行文件中,它可以按照这个顺序创建(或按照任何其他顺序,只要相对顺序在每个.cpp内得到尊重):

Image2

因为如果不同的静态全局对象之间存在关系,例如在其析构函数中使用其他对象,可能会在全局变量的析构函数中使用来自另一个编译单元的另一个全局对象,但该对象已被销毁(稍后已经构建), 这就很重要了。
隐藏依赖项和*测试用例*
我试图找到在这个示例中将要使用的源代码,但我找不到它(无论如何,它都是用来说明单例模式的使用,尽管该示例适用于全局和静态变量)。 隐藏依赖关系还会创建与控制对象行为有关的新问题,如果它依赖于全局变量的状态。
想象一下您拥有一个付款系统,并且您想测试它以查看它的工作方式,因为您需要进行更改,而代码来自另一个人(或几年前的代码)。 您打开一个新的主功能,然后调用提供银行支付服务的全局对象的相应函数,并且结果是您输入您的数据并收费。 在简单测试中,我如何使用生产版本? 我怎么做一个简单的付款测试?

询问其他同事后,发现在开始收集过程之前必须“标记为真”,即一个全局布尔值,表示我们是否处于测试模式。提供支付服务的对象依赖于另一个提供支付方式的对象,并且该依赖关系以程序员看不见的方式发生。

换句话说,全局变量(或单例)使得无法进入“测试模式”,因为不能将全局变量替换为“测试”实例(除非修改创建或定义该代码的代码)。我们假设测试是在母代码没有修改的情况下进行的。

解决方案

这可以通过所谓的*依赖注入*来解决,它包括在构造函数或相应方法中传递对象需要的所有依赖项作为参数。这样,程序员可以**看到**他需要编写的代码,从而使开发人员节省了大量时间。

如果有太多的全局对象,并且需要它们的函数参数也很多,那么您可以始终将您的“全局对象”分组到一个类中,样式为*工厂*,该类构建并返回您想要的“全局对象”(模拟),将工厂作为参数传递给需要全局对象作为依赖项的对象。

如果您进入测试模式,可以始终创建一个测试工厂(返回相同对象的不同版本),并将其作为参数传递,而无需修改目标类。
但它是否总是不好呢?
不一定,全局变量可能有好的用途。例如,常量值(PI值)。作为常量值,不存在由其他模块的任何类型的修改导致在程序某一点上不知道其值的风险。此外,常量值倾向于是原始的,并且不太可能更改其定义。
在这种情况下,使用全局变量更方便,以避免将变量作为参数传递,简化函数的签名。
另一个可以是非侵入性的“全局”服务,例如记录类(保存发生在文件中的内容,通常是可选和可配置的程序,因此不会影响应用程序的核心行为),或std :: cout,std :: cin或std :: cerr,也是全局对象。

任何其他事情,即使它的生命周期几乎与程序相同,也始终将其作为参数传递。即使变量在模块中是全局的,在没有任何其他访问的情况下仅在其中,但在任何情况下,依赖关系始终作为参数存在。

回答者:Peregring-lk


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接