我希望一些变量在整个项目中都是全局的,并且可以以各种形式访问。我怎样才能做到这一点?
8 回答
是的,您可以使用静态类。像这样:
static class Global
{
private static string _globalVar = "";
public static string GlobalVar
{
get { return _globalVar; }
set { _globalVar = value; }
}
}
并使用任何你可以写的地方:
GlobalClass.GlobalVar = "any string value"
这里的共识是将全局变量作为静态成员放在静态类中。当您创建一个新的 Windows 窗体应用程序时,它通常带有一个程序类 (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();
}
}
或者你可以把你的全局变量放在app.config
单程,
解决方案资源管理器 > 您的项目 > 属性 > Settings.Settings。单击此文件并添加从 IDE 定义您的设置。
通过以下方式访问它们
Properties.Settings.Default.MySetting = "hello world";
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
}
}
如果您使用的是 Visual C#,您需要做的就是在 Program.cs 中添加一个继承 Form 的类,并将所有从 Form 继承的类更改为您在每个 Form*.cs 中的类。
//Program.cs
public class Forms : Form
{
//Declare your global valuables here.
}
//Form1.cs
public partial class Form1 : Forms //Change from Form to Forms
{
//...
}
当然,可能有一种方法可以在不修改 Form 的情况下扩展类。如果是这种情况,您需要做的就是扩展它!由于所有的表单都是默认继承的,所以里面声明的所有值都会自动变成全局的!祝你好运!!!
他们已经回答了如何使用全局变量。
我会告诉你为什么使用全局变量是一个坏主意,因为这个问题是在西班牙语的 stackoverflow 中进行的。
西班牙语文本的明确翻译:
变化的影响
全局变量的问题在于它们创建了隐藏的依赖关系。对于大型应用程序,您自己不知道/不记得/您清楚自己拥有的对象及其关系。
因此,您无法清楚地了解全局变量正在使用多少个对象。如果您想更改全局变量的某些内容,例如,它的每个可能值的含义,或者它的类型?该更改将影响多少个类或编译单元?如果金额很小,则可能值得进行更改。如果影响很大,可能值得寻找另一种解决方案。
但有什么影响?因为全局变量可以在代码中的任何地方使用,所以很难测量它。
此外,请始终尝试使变量的生命周期尽可能短,以使使用该变量的代码量尽可能少,从而更好地了解其用途以及修改者。
全局变量在程序运行期间持续存在,因此,任何人都可以使用该变量来读取它,或者更糟糕的是,更改它的值,这使得在任何给定程序中知道该变量将具有什么值变得更加困难观点。.
破坏令
另一个问题是破坏的顺序。变量总是以其创建的相反顺序被销毁,无论它们是局部变量还是全局/静态变量(一个例外是原始类型、int
、enum
s 等,如果它们是全局/静态的,则在它们结束程序之前永远不会被销毁) .
问题是很难知道全局(或静态)变量的构造顺序。原则上是不确定的。
如果你所有的全局/静态变量都在一个编译单元中(也就是说,你只有一个.cpp
),那么构造的顺序和写的顺序是一样的(也就是说,之前定义的变量,都是在之前构建的)。
但是如果你有不止一个.cpp
,每个都有自己的全局/静态变量,全局构造顺序是不确定的。当然,每个编译单元(每个.cpp
)中的顺序尤其受到尊重:如果全局变量A
定义在之前B
,A
则将在之前构建B
,但是可能会初始化其他变量之间的A
和。例如,如果您有三个具有以下全局/静态变量的单元:B
.cpp
在可执行文件中,它可以按以下顺序创建(或以任何其他顺序,只要在 each 中尊重相对顺序.cpp
):
为什么这很重要?因为如果不同的静态全局对象之间存在关系,例如,一些在其析构函数中使用其他对象,也许在全局变量的析构函数中,您使用来自另一个编译单元的另一个全局对象,该对象结果已经被销毁(有后来建的)。
隐藏的依赖和*测试用例*
我试图找到我将在这个例子中使用的源代码,但是我找不到它(无论如何,它是为了举例说明单例的使用,虽然这个例子适用于全局变量和静态变量)。如果对象依赖于全局变量的状态,隐藏的依赖关系也会产生与控制对象行为相关的新问题。
假设您有一个支付系统,并且您想测试它以了解它是如何工作的,因为您需要进行更改,并且代码来自另一个人(或您的,但来自几年前)。您打开一个新的main
,然后调用提供银行卡支付服务的全局对象的相应函数,结果是您输入了数据,他们向您收费。在一个简单的测试中,我如何使用生产版本?如何进行简单的付款测试?
在询问了其他同事之后,事实证明您必须在开始收集过程之前“标记为真”,这是一个指示我们是否处于测试模式的全局布尔值。你的提供支付服务的对象依赖于另一个提供支付方式的对象,而这种依赖对程序员来说是无形的。
换句话说,全局变量(或单例)使得无法传递到“测试模式”,因为全局变量不能被“测试”实例替换(除非您修改创建或定义所述代码的代码)。全局变量,但我们假设测试是在不修改母代码的情况下完成的)。
解决方案
这是通过所谓的*依赖注入*解决的,它包括将对象在其构造函数或相应方法中所需的所有依赖项作为参数传递。通过这种方式,程序员**看到**发生在他身上的事情,因为他必须用代码编写它,从而使开发人员获得了很多时间。
如果全局对象太多,并且需要它们的函数中的参数太多,您总是可以将“全局对象”分组到一个类中,样式 * factory *,该类构建并返回“全局对象”的实例"(模拟)你想要的,将工厂作为参数传递给需要全局对象作为依赖的对象。
如果您传递到测试模式,您始终可以创建一个测试工厂(它返回相同对象的不同版本),并将其作为参数传递,而无需修改目标类。
但总是不好吗?
不一定,全局变量可能有很好的用途。比如常数值(PI值)。作为一个常数值,不存在通过来自另一个模块的任何类型的修改而在程序中的给定点不知道其值的风险。此外,常数值往往是原始的,不太可能改变它们的定义。
在这种情况下,更方便的是使用全局变量来避免将变量作为参数传递,从而简化函数的签名。
另一个可以是非侵入性的“全局”服务,例如日志记录类(保存文件中发生的事情,通常在程序中是可选的和可配置的,因此不会影响应用程序的核行为),或者std :: cout
,std :: cin
或者std :: cerr
,也是全局对象。
任何其他事物,即使它的生命周期几乎与程序的生命周期一致,也始终将其作为参数传递。甚至变量在模块中也可以是全局的,仅在模块中没有任何其他访问权限,但是在任何情况下,依赖项始终作为参数存在。
回答者:Peregring-lk