我正在尝试在使用C++编写的.NET应用程序中使字符串持久化(即文件路径),并在应用程序启动时读取它,在退出时写入它。
我正在努力寻找正确的方法。网络搜索指向了ConfigurationSettings和ConfigurationManager对象。似乎第一个是只读的,而第二个在Configuration参考文献中未找到(框架3.5)。
我知道可以执行显式读取/写入到注册表或外部文件,但我更喜欢一种更标准的方式。我不希望这需要超过两行代码。
我是否走上了正确的道路?
我正在尝试在使用C++编写的.NET应用程序中使字符串持久化(即文件路径),并在应用程序启动时读取它,在退出时写入它。
我正在努力寻找正确的方法。网络搜索指向了ConfigurationSettings和ConfigurationManager对象。似乎第一个是只读的,而第二个在Configuration参考文献中未找到(框架3.5)。
我知道可以执行显式读取/写入到注册表或外部文件,但我更喜欢一种更标准的方式。我不希望这需要超过两行代码。
我是否走上了正确的道路?
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Linq;
namespace DesktopApp1 {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Config myConfig = new Config();
myConfig.Load();
//Change settings during the livetime of the application
myConfig.SomethingPath = @"C:\Temp\Foo\TestUser.dat";
myConfig.PortableMode = false;
//Write it when closing the application
myConfig.Save();
}
}
internal class Config {
//Private Fields
private AppOrUserConfig _Config;
private Boolean _IsUserConfig;
private String _AppConfigPath;
private String _UserConfigPath;
public void Load() {
AppOrUserConfig myDefaultConfig = new AppOrUserConfig();
AppOrUserConfig myAppConfig = new AppOrUserConfig(AppConfigPath, myDefaultConfig);
if (myAppConfig.PortableMode) {
_Config = myAppConfig;
_IsUserConfig = false;
} else {
_Config = new AppOrUserConfig(UserConfigPath, myAppConfig);
_IsUserConfig = true;
}
}
public Boolean Save() {
CheckLoad();
String myFilePath = IsUserConfig ? UserConfigPath : AppConfigPath;
try {
String myContent = _Config.XmlContent;
String myFolder = Path.GetDirectoryName(myFilePath);
Directory.CreateDirectory(myFolder);
File.Delete(myFilePath);
File.WriteAllText(myFilePath, myContent, new UTF8Encoding(true));
return true;
} catch {
}
return false;
}
public Boolean PortableMode {
get {
CheckLoad();
return _Config.PortableMode;
}
set {
CheckLoad();
if (PortableMode == value) return;
if (value) {
_Config.PortableMode = true;
_IsUserConfig = false;
Save();
} else {
String myPath = SomethingPath;
_Config.PortableMode = false;
Save();
Load();
SomethingPath = myPath;
}
}
}
public String SomethingPath {
get {
CheckLoad();
return _Config.SomethingPath;
}
set {
CheckLoad();
_Config.SomethingPath = value;
}
}
private String AppConfigPath {
get {
String myResult = _AppConfigPath;
if (myResult == null) {
myResult = Assembly.GetEntryAssembly().EntryPoint.DeclaringType.Module.FullyQualifiedName + ".config";
_AppConfigPath = myResult;
}
return myResult;
}
}
private String UserConfigPath {
get {
String myResult = _UserConfigPath;
if (myResult == null) {
myResult = Path.Combine(Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Cragin\FooApp"), Path.GetFileName(AppConfigPath));
_UserConfigPath = myResult;
}
return myResult;
}
}
private Boolean IsUserConfig {
get {
return _IsUserConfig;
}
}
private void CheckLoad() {
if (_Config == null) throw new InvalidOperationException(@"Call method ""Load()"" first.");
}
}
internal class AppOrUserConfig {
//Private Fields
private XDocument _Xml;
//Constructors
public AppOrUserConfig() {
_Xml = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
<startup>
<supportedRuntime version=""v2.0.50727""/>
</startup>
<appSettings>
<add key=""PortableMode"" value=""Off""/>
<add key=""SomethingPath"" value=""C:\ProgramData\Cragin\SomeLibrary""/>
</appSettings>
</configuration>");
}
public AppOrUserConfig(String filePath, AppOrUserConfig defaultValue) : this() {
XDocument myXml = null;
try {
myXml = XDocument.Parse(File.ReadAllText(filePath));
} catch {
return;
}
AppOrUserConfig myDummy = new AppOrUserConfig(myXml, defaultValue);
PortableMode = myDummy.PortableMode;
SomethingPath = myDummy.SomethingPath;
}
public AppOrUserConfig(XDocument xml, AppOrUserConfig defaultValue) : this() {
if (defaultValue == null) defaultValue = new AppOrUserConfig();
if (xml == null) {
PortableMode = defaultValue.PortableMode;
SomethingPath = defaultValue.SomethingPath;
return;
}
AppOrUserConfig myDummy = new AppOrUserConfig();
myDummy._Xml = xml;
PortableMode = myDummy.GetPortableMode(defaultValue.PortableMode);
SomethingPath = myDummy.GetSomethingPath(defaultValue.SomethingPath);
}
public Boolean PortableMode {
get {
return GetPortableMode(false);
}
set {
(from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "PortableMode" select e).Last().Attribute("value").Value = value ? "on" : "off";
}
}
public String SomethingPath {
get {
return GetSomethingPath(@"C:\ProgramData\Cragin\SomeLibrary");
}
set {
(from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "SomethingPath" select e).Last().Attribute("value").Value = value ?? "";
}
}
public String XmlContent {
get {
return _Xml.ToString(SaveOptions.None);
}
}
private Boolean GetPortableMode(Boolean defaultValue) {
try {
String myString = (from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "PortableMode" select e).Last().Attribute("value").Value;
return ToBoolean(myString);
} catch {
PortableMode = defaultValue;
return defaultValue;
}
}
private String GetSomethingPath(String defaultValue) {
try {
return (from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "SomethingPath" select e).Last().Attribute("value").Value;
} catch {
SomethingPath = defaultValue;
return defaultValue;
}
}
private static Boolean ToBoolean(String value) {
value = value.Trim();
switch (value.Length) {
case 1:
if (value[0] == '0') return false;
if (value[0] == '1') return true;
break;
case 5:
if (value.ToLowerInvariant() == "false") return false;
break;
case 4:
if (value.ToLowerInvariant() == "true") return true;
break;
case 3:
if (value.ToLowerInvariant() == "off") return false;
break;
case 2:
if (value.ToLowerInvariant() == "on") return true;
break;
}
throw new FormatException();
}
}
}
我已经通过ConfigurationManager自己解决了这个问题,受到这个例子的启发:https://learn.microsoft.com/en-us/dotnet/api/system.configuration.appsettingssection?view=netframework-4.8
我的实现是有效的,但我不理解它。
看起来你可能想要使用独立存储:
对于桌面应用程序,独立存储是一种数据存储机制,通过定义将代码与保存的数据关联的标准化方式,提供隔离和安全性。标准化还提供其他好处。管理员可以使用设计用于操作独立存储的工具来配置文件存储空间、设置安全策略和删除未使用的数据。使用独立存储,你的代码不再需要唯一路径来指定文件系统中的安全位置,数据也受到其他仅具有独立存储访问权限的应用程序的保护。不需要硬编码信息来指示应用程序的存储区域位于何处。
如上所述,你不必担心各种计算机之间的潜在差异或者想出一个可能脆弱的专有解决方案。
你的解决方案,虽然可能有效,但似乎属于“专有”类别,并且可能不是配置管理器的最佳用法。