【问题标题】:Maintain a variable value between program runs在程序运行之间保持变量值
【发布时间】:2012-11-09 05:33:44
【问题描述】:

我有一个简单的 c# 控制台应用程序,每 5 分钟安排一次。程序的每次调用都需要最后一次运行的输出。

我现在正在做的是使用一个文本文件并将结果存储在其中。下次运行时,它会打开文本文件并知道上一次运行的输出。

还有其他不需要任何此类文本文件的方法吗? 比如维护一个会话变量等?

【问题讨论】:

  • 你可以使用无数种方法;数据库、注册表、任意文件存储等,是否有理由偏离文本文件存储机制?
  • 我支持@QuintinRobinson,这将有助于理解您为什么认为文件不是最佳解决方案。
  • 它是因为我不希望用户看到我的程序正在创建一个文本文件。让程序休眠似乎是个好主意。
  • @QuintinRobinson,大多数企业解决方案都使用 pid lock-file 来禁止并发执行。为什么你认为 IO-File 不好?
  • @Akshay。看看我的回答,该文件将在 appdata 文件夹中创建。有一个应用程序数据的好地方。你也可以加密文件。

标签: c# .net windows-applications stateful


【解决方案1】:

您可以使用设置文件。每次程序关闭时,只需将设置文件添加到您的项目并保存您要存储的值。程序启动时检查设置文件中的值。

【讨论】:

  • 并发应用执行怎么样?
  • @pylover 我提供了一个简单的解决方案,可以满足他的需求。他从未说过需要并发执行。
  • @user1739957 你的解决方案也很棒!
【解决方案2】:

您必须将数据保存在某个地方。控制台应用程序没有会话变量(甚至会话)。您可能是指环境变量。如果将其存储在环境变量中,则程序必须从相同的环境(即从相同的控制台窗口)运行。如果机器崩溃,环境变量就会丢失。最好有一个文件。

如果它每 5 分钟运行一次,你能让程序休眠直到它需要再次运行吗?然后数据将在内存中可用。如果机器崩溃仍然是一个问题,因此您仍然可能需要保留一个文件作为备份。

如果您不希望用户看到一个文件,并且它不是 太多 太多数据(尽管几个 K 字节可能是可行的),正如@Quintin Robinson 建议的那样,您可以使用注册表。只需确保您写入的内容合乎逻辑并且您拥有正确的权限即可。

如果您不希望用户能够看到文件中的内容,您可以打乱内容以使其不可读。如果您使用加密,您将需要本地密钥来解密,以便熟练或坚定的攻击者仍然能够获取文件。最好只压缩数据并称其为好。

如果您不希望用户能够轻松更改文件中的内容,您可以将校验和、哈希或 HMAC 与数据一起存储。您必须在本地验证它,这意味着这可能会受到攻击,但应该阻止普通用户进行位黑客攻击。

当然,您可以结合注册表存储、加扰和校验和,具体取决于您的需要和关注点。

我考虑过提及 PStor 和 CryptProtectData/CryptUnprotectData,但后来我意识到它们的安全性是基于 USER 的,因此在这里无济于事。

如果机器连接到 Internet,您可以考虑使用云存储,但我不知道这是否适合您的应用程序。

【讨论】:

  • 我喜欢听软件顾问的意见。这么彻底的回答
【解决方案3】:

首先使用mutex lock解决方案强制app同时只运行一个实例。

然后创建一个可序列化的类来保存应用程序状态和一个帮助类来加载并将其保存到文件中。参见示例:

[XmlRoot("RegexTesterPersistantSettings")]
[Serializable]
public class State
{
    public State()
    {
        this.Pattern = string.Empty;
        this.TestString = string.Empty;
        this.Options = 0;
    }
    [XmlElement("Pattern")]
    public string Pattern{get;set;}

    [XmlElement("TestString")]
    public string TestString{get;set;}

    [XmlElement("Options")]
    public int Options { get; set; }

    public override int GetHashCode()
    {
        return this.Options.GetHashCode() ^ this.Pattern.GetHashCode() ^ this.TestString.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        State anotherState = obj as State;
        if (anotherState == null)
        {
            return false;
        }

        return this.Equals(anotherState);
    }

    public bool Equals(State anotherState)
    {
        return this.GetHashCode() == anotherState.GetHashCode();
    }

    public static bool operator ==(State a, State b)
    {
        // If both are null, or both are same instance, return true.
        if (System.Object.ReferenceEquals(a, b))
        {
            return true;
        }

        // If one is null, but not both, return false.
        if (((object)a == null) || ((object)b == null))
        {
            return false;
        }
        return a.Equals(b);
    }

    public static bool operator !=(State a, State b)
    {
        return !a.Equals(b);
    }

}

public class PersistantHelper
{
    private string filename;
    private State _state;

    public PersistantHelper(string xmlFilename = "RegexTesterSettings")
    {
        string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
        this.filename  = Path.Combine(appDataPath, xmlFilename);
    }

    private XmlSerializer _serializer;
    private XmlSerializer Serializer
    {
        get
        {
            if (this._serializer == null)
            {
                this._serializer = new XmlSerializer(typeof(State));
            }
            return this._serializer;
        }
    }

    private void SaveState(State state)
    {
        if (File.Exists(this.filename))
        {
            File.Delete(this.filename);
        }
        var stream  = new FileStream(this.filename,  FileMode.OpenOrCreate, FileAccess.Write,FileShare.None);
        this.Serializer.Serialize(stream, state);
        stream.Close();
    }

    public State State
    {
        get
        {
            if (this._state == null)
            {
                this._state = this.GetState();
            }
            return this._state;
        }
        set 
        {
            if (this.State != value)
            {
                this.SaveState(value);
            }
        }
    }

    private State dummyState = new State() { Options = 0 };
    private State GetState()
    {
        if (!File.Exists(this.filename))
        {
            return this.dummyState;
        }
        Stream stream = null;
        try
        {
            stream = new FileStream(this.filename, FileMode.Open, FileAccess.Read,FileShare.None);
            var o = this.Serializer.Deserialize(stream);
            return (State)o;
        }
        catch
        {
            return this.dummyState;
        }
        finally
        {
            if (stream != null)
            {
                stream.Close();
            }
        }

    }
}

然后从您的应用中加载并保存状态:

    private PersistantHelper persistantHelper;
    public frmTester()
    {
        InitializeComponent();
        this.persistantHelper = new PersistantHelper();
        .
        .
        .
    }

private void LoadPersistantData()
{
    State state = this.persistantHelper.State;
    this.txtPattern.Text = state.Pattern;
    this.txtTest.Text = state.TestString;
    foreach (Control c in this.pnlOptions.Controls)
    {
        if (c is CheckBox)
        {
            var chk = c as CheckBox;
            int tag = int.Parse(c.Tag.ToString());
            chk.Checked = (state.Options & tag) == tag;
        }
    }
}


private void SavePersistantData()
{
    this.persistantHelper.State = new State()
    {
        Options = (int)this.GetOptions(),
        Pattern = txtPattern.Text,
        TestString = txtTest.Text
    };
}       

【讨论】:

  • 我不知道为什么这是公认的答案。它的设计方式太过分了。最初的问题也没有提到并发进程。
  • 不考虑并发,没有保证,可能会失败。
猜你喜欢
  • 2022-10-19
  • 1970-01-01
  • 2017-03-30
  • 1970-01-01
  • 2011-10-04
  • 2015-07-11
相关资源
最近更新 更多