C# 通过输出表单创建全局变量

C# 通过输出表单创建全局变量,c#,.net-4.0,C#,.net 4.0,我试图通过所有windows窗体将用户名和其他一些信息保存为全局变量,这些窗体从登录窗体开始,比如usernameI搜索并得出以下代码 首先,我创建一个名为globals的单独类,如下所示 public static class globals { public static string userName { get; set; } } 然后,我在登录成功时设置该变量,如下所示 Checks.globals.userName = TB_USER_NAME.Text; 没什么问题

我试图通过所有windows窗体将用户名和其他一些信息保存为全局变量,这些窗体从登录窗体开始,比如
username
I搜索并得出以下代码

首先,我创建一个名为
globals
的单独类,如下所示

public static class globals
{
    public static string userName { get; set; }
}
然后,我在登录成功时设置该变量,如下所示

Checks.globals.userName = TB_USER_NAME.Text;
没什么问题

  • 我是否必须使财产用户名受到保护,或者可能是私有的

    public static string userName { get; private set; }
    
  • 是否在首次初始化后不会再次设置该值

  • 还有更好的事要做吗


听起来您在问,“如何强制一个变量只设置一次”。如果是这种情况,您可以创建一个备份字段来存储该值,并且在属性
set
方法中,您可以首先检查备份字段是否为
null
。如果是,则设置该值,如果不是,则不要执行任何操作。以这种方式,支持字段只设置一次:

private static string _username = null;

public static string UserName
{
    get { return _userName; }
    set { if (_username == null) _username = value; }
}
另一个选项是将
setter
设置为私有,并提供不同的方法来设置值。这导致了一种奇怪的设计,但它确实使
UserName
属性为只读,这将防止意外赋值(这将导致编译时错误)

例如:

// UserName is a Read-Only property; it can't be assigned a value directly
public static string UserName { get; private set; }

// Anyone can change UserName here, but they have to intentionally call this method to do so
public static void SetUserName(string userName)
{
    UserName = userName;
}
我试图保存用户名和一些其他信息作为全局变量通过所有windows窗体从登录窗体开始,如用户名

这在C#中被认为是一种糟糕的编程实践。依赖全局状态会使程序更难推理,也更难修改

考虑另一种方法;如果程序中有许多类实例需要访问相同的信息,那么它们都可以保留对状态对象的引用,而不是对全局状态的引用

首先,我创建了一个名为globals的单独类,如下所示

如果你执意要使用全局变量,那就是正确的方法。但是你应该遵循C标准,把它叫做
Globals
,而不是
Globals

同样地:

public static string userName { get; set; }
应该是
用户名
,而不是
用户名

然后,我在登录成功时设置该变量,如下所示

同样,使用适当的C#命名约定。在C语言中,我们不会到处喊蛇

我是否必须使财产用户名受到保护,或者可能是私有的

public static string userName { get; private set; }
你不能让它受到保护;这是一个静态类!受保护意味着派生类可以访问,从静态类派生是非法的

将其设置为私有将使其无法从类外访问,这与您想要的相反

所以,不,不要那样做。你能解释一下为什么你认为这可能是个好主意吗?因为你有一些错误的信念,应该予以澄清

是否在首次初始化后不会再次设置该值

设置的次数与您设置的次数相同这就是“全球国家”的含义,也是为什么这是一个坏主意的原因。现在你必须确保你的程序只设置一次值,如果你想要的话,并且你必须确保在你的程序中全局。这就是为什么全局状态对可维护性不利的原因:因为它将适合本地分析的问题转化为需要整个程序分析的问题

如果您想检测全局状态设置多次的bug,那么创建更多全局状态:您需要全局状态“my global state has set one”。然后,您可以在集合上检查该状态,如果设置多次,则会使程序崩溃。或者忽略第二组,或者其他,如果你喜欢隐藏你的bug而不是修复它们

还有更好的事要做吗

对。放弃需要维护全局状态的体系结构。在实例变量中维护状态

我是否必须使财产用户名受到保护,或者可能是私有的

public static string userName { get; private set; }
如果将属性用户名设置为受保护或私有,则无法通过属性设置值

是否在首次初始化后不会再次设置该值

根据您的逻辑,需要仔细考虑,因为这是一个全局值

还有更好的事要做吗

如果必须使用全局,我将使用全局对象

当需要一个对象来协调整个系统中的操作时,这非常有用。这个概念有时被推广到只有一个对象存在时运行效率更高的系统,或者将实例化限制在一定数量的对象上的系统

public class Globals
{
    private static Globals _obj;
    public static Globals Current {
        get {
            if (_obj == null)
                _obj = new Globals();
            return _obj;
        }
    }
    private Globals() { }

    private string _username;

    public string UserName { get { return _username; } }

    public void SetUserName(string userName) {
        this._username = userName;
    }
}
您可以使用
Globals.Current
获取全局对象。 如果您想设置
UserName
只需调用
SetUserName
方法即可

Globals.Current.SetUserName("test"); //set the username
Globals.Current.UserName; // get the username

我尝试了它,但当我设置它的值时,出现了一个错误。\n属性或索引器的Checks.globals.\u userName'不能在此上下文中使用,因为set访问器不可访问。\n是的,对不起,出于某种原因,我将setter设置为
private
,这不是我的意图。现在应该可以了。但请注意Eric Lippert的建议。我的回答可能会“解决”您的问题,但我认为实际问题比这个(程序设计)更大。我在get部分遇到一个错误,它说,
{无法计算表达式,因为当前线程处于堆栈溢出状态。}
@sam:您编写了一个setter或getter,可以调用自身。不要那样做!谢谢你提供的有用信息,我真的很感激你,耐心点,我的朋友,不是每个人都知道你有经验:)单身是一个很好的方法,因为它可以让你逐渐摆脱静态的全局状态;您可以编写所有相关代码来处理实例中的状态,然后该实例是否为单例就不需要使用者关心了!