Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果user.config中有Int32[]属性,则在使用CustomSettingsProvider时会出现无效的强制转换异常_C#_.net_Winforms_App Config_User.config - Fatal编程技术网

C# 如果user.config中有Int32[]属性,则在使用CustomSettingsProvider时会出现无效的强制转换异常

C# 如果user.config中有Int32[]属性,则在使用CustomSettingsProvider时会出现无效的强制转换异常,c#,.net,winforms,app-config,user.config,C#,.net,Winforms,App Config,User.config,我遵循并创建了我的CustomSettingsProvider,以除去存储user.config文件的路径中的“\u url\u somehash”部分。现在,我的设置存储在\CompanyName\ProductName\Version\user.config中 我的user.config文件(在创建CustomSettingsProvider之前由我的应用程序编写)包含一个Int32[]属性,该属性由默认SettingsProvider正确存储和加载。当我使用CustomSettingsPr

我遵循并创建了我的CustomSettingsProvider,以除去存储user.config文件的路径中的“\u url\u somehash”部分。现在,我的设置存储在\CompanyName\ProductName\Version\user.config中

我的user.config文件(在创建CustomSettingsProvider之前由我的应用程序编写)包含一个Int32[]属性,该属性由默认SettingsProvider正确存储和加载。当我使用CustomSettingsProvider时,会出现以下异常:

Exception InvalidCastException
Source = mscorlib
Message = Invalid cast from 'System.String' to 'System.Int32[]'.
TargetSite = System.Object DefaultToType(System.IConvertible, System.Type, System.IFormatProvider)
Stack =
    System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
    System.String.System.IConvertible.ToType(Type type, IFormatProvider provider)
    System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
    System.Convert.ChangeType(Object value, Type conversionType)
    MyApp.Interface.CustomSettingsProvider.GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) in d:\Users\angelo\Documents\Visual Studio 2013\Projects\MyApp\MyApp\Interface\CustomSettingsProvider.cs:line 112
    System.Configuration.SettingsBase.GetPropertiesFromProvider(SettingsProvider provider)
    System.Configuration.SettingsBase.GetPropertyValueByName(String propertyName)
    System.Configuration.SettingsBase.get_Item(String propertyName)
    System.Configuration.ApplicationSettingsBase.GetPropertyValue(String propertyName)
    System.Configuration.ApplicationSettingsBase.get_Item(String propertyName)
    MyApp.Properties.Settings.get_UpgradeRequired() in d:\Users\angelo\Documents\Visual Studio 2013\Projects\MyApp\MyApp\Properties\Settings.Designer.cs:line 31
    MyApp.Interface.Program.Run() in d:\Users\angelo\Documents\Visual Studio 2013\Projects\MyApp\MyApp\Interface\Program.cs:line 51
    MyApp.Interface.Program.Main() in d:\Users\angelo\Documents\Visual Studio 2013\Projects\MyApp\MyApp\Interface\Program.cs:line 34
我如何解决这个问题?在更一般的情况下,如何以与使用默认设置Provider相同的方式存储集合和类

这是我的CustomSettingsProvider类的完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Reflection;
using System.Xml.Linq;
using System.IO;

// ==>>>>  https://stackoverflow.com/questions/2265271/custom-path-of-the-user-config
// https://stackoverflow.com/questions/1947185/c-sharp-get-special-folder

namespace MyApp.Interface
{
    class CustomSettingsProvider : SettingsProvider
    {
        #region Helper struct
        /// <summary>
        /// Helper struct.
        /// </summary>
        internal struct SettingStruct
        {
            internal string name;
            internal string serializeAs;
            internal string value;
        } 
        #endregion
        #region Constants
        const string NAME = "name";
        const string SERIALIZE_AS = "serializeAs";
        const string CONFIG = "configuration";
        const string USER_SETTINGS = "userSettings";
        const string SETTING = "setting"; 
        #endregion
        #region Fields
        bool _loaded; 
        #endregion
        #region Properties
        /// <summary>
        /// Override.
        /// </summary>
        public override string ApplicationName { get { return System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name; } set { /*do nothing*/ } } 
        /// <summary>
        /// The setting key this is returning must set before the settings are used.
        /// e.g. <c>Properties.Settings.Default.SettingsKey = @"C:\temp\user.config";</c>
        /// </summary>
        private string UserConfigPath
        {
            get
            {
                System.Diagnostics.FileVersionInfo versionInfo;
                string strUserConfigPath, strUserConfigFolder;

                strUserConfigPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.Create);
                versionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location);
                strUserConfigPath = Path.Combine(strUserConfigPath, versionInfo.CompanyName, versionInfo.ProductName, versionInfo.ProductVersion, "user.config");
                strUserConfigFolder = Path.GetDirectoryName(strUserConfigPath);
                if(!Directory.Exists(strUserConfigFolder))
                    Directory.CreateDirectory(strUserConfigFolder);
                return strUserConfigPath;
            }
        }
        /// <summary>
        /// In memory storage of the settings values
        /// </summary>
        private Dictionary<string, SettingStruct> SettingsDictionary { get; set; }
        #endregion
        #region Constructor
        /// <summary>
        /// Loads the file into memory.
        /// </summary>
        public CustomSettingsProvider()
        {
            SettingsDictionary = new Dictionary<string, SettingStruct>();
        } 
        /// <summary>
        /// Override.
        /// </summary>
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            base.Initialize(ApplicationName, config);
        }
        #endregion
        /// <summary>
        /// Must override this, this is the bit that matches up the designer properties to the dictionary values
        /// </summary>
        /// <param name="context"></param>
        /// <param name="collection"></param>
        /// <returns></returns>
        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
        {
            //load the file
            if(!_loaded)
            {
                _loaded = true;
                LoadValuesFromFile();
            }
            //collection that will be returned.
            SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
            //iterate thought the properties we get from the designer, checking to see if the setting is in the dictionary
            foreach(SettingsProperty setting in collection)
            {
                SettingsPropertyValue value = new SettingsPropertyValue(setting);
                value.IsDirty = false;

                //need the type of the value for the strong typing
                var t = Type.GetType(setting.PropertyType.FullName);

                if(SettingsDictionary.ContainsKey(setting.Name))
                {
                    value.SerializedValue = SettingsDictionary[setting.Name].value;
                    value.PropertyValue = Convert.ChangeType(SettingsDictionary[setting.Name].value, t);
                }
                else //use defaults in the case where there are no settings yet
                {
                    value.SerializedValue = setting.DefaultValue;
                    value.PropertyValue = Convert.ChangeType(setting.DefaultValue, t);
                }

                values.Add(value);
            }
            return values;
        }
        /// <summary>
        /// Must override this, this is the bit that does the saving to file.  Called when Settings.Save() is called
        /// </summary>
        /// <param name="context"></param>
        /// <param name="collection"></param>
        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
        {
            //grab the values from the collection parameter and update the values in our dictionary.
            foreach(SettingsPropertyValue value in collection)
            {
                var setting = new SettingStruct()
                {
                    value = (value.PropertyValue == null ? String.Empty : value.PropertyValue.ToString()),
                    name = value.Name,
                    serializeAs = value.Property.SerializeAs.ToString()
                };
                if(!SettingsDictionary.ContainsKey(value.Name))
                    SettingsDictionary.Add(value.Name, setting);
                else
                    SettingsDictionary[value.Name] = setting;
            }
            //now that our local dictionary is up-to-date, save it to disk.
            SaveValuesToFile();
        }
        /// <summary>
        /// Loads the values of the file into memory.
        /// </summary>
        private void LoadValuesFromFile()
        {
            string strUserConfigPath;
            strUserConfigPath = UserConfigPath;
            //if the config file is not where it's supposed to be create a new one.
            if(!File.Exists(strUserConfigPath))
                CreateEmptyConfig(strUserConfigPath);
            //System.Security.Policy.StrongName strongName = new System.Security.Policy.StrongName(
            //ClickOnce
            //load the xml
            var configXml = XDocument.Load(UserConfigPath);

            //get all of the <setting name="..." serializeAs="..."> elements.
            var settingElements = configXml.Element(CONFIG).Element(USER_SETTINGS).Element(typeof(Properties.Settings).FullName).Elements(SETTING);

            //iterate through, adding them to the dictionary, (checking for nulls, xml no likey nulls)
            //using "String" as default serializeAs...just in case, no real good reason.
            foreach(var element in settingElements)
            {
                var newSetting = new SettingStruct()
                {
                    name = element.Attribute(NAME) == null ? String.Empty : element.Attribute(NAME).Value,
                    serializeAs = element.Attribute(SERIALIZE_AS) == null ? "String" : element.Attribute(SERIALIZE_AS).Value,
                    value = element.Value ?? String.Empty
                };
                SettingsDictionary.Add(element.Attribute(NAME).Value, newSetting);
            }
        }
        /// <summary>
        /// Creates an empty user.config file...looks like the one MS creates.  
        /// This could be overkill a simple key/value pairing would probably do.
        /// </summary>
        private void CreateEmptyConfig(string strUserConfigPath)
        {
            Configuration config1;

            config1 = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
            if(File.Exists(config1.FilePath))
            {
                File.Copy(config1.FilePath, strUserConfigPath);
            }
            else
            {
                string s = Properties.Settings.Default.LastLoadedImage;
                var doc = new XDocument();
                var declaration = new XDeclaration("1.0", "utf-8", "true");
                var config = new XElement(CONFIG);
                var userSettings = new XElement(USER_SETTINGS);
                var group = new XElement(typeof(Properties.Settings).FullName);
                userSettings.Add(group);
                config.Add(userSettings);
                doc.Add(config);
                doc.Declaration = declaration;
                doc.Save(strUserConfigPath);
            }
        }
        /// <summary>
        /// Saves the in memory dictionary to the user config file
        /// </summary>
        private void SaveValuesToFile()
        {
            //load the current xml from the file.
            var import = XDocument.Load(UserConfigPath);

            //get the settings group (e.g. <Company.Project.Desktop.Settings>)
            var settingsSection = import.Element(CONFIG).Element(USER_SETTINGS).Element(typeof(Properties.Settings).FullName);

            //iterate though the dictionary, either updating the value or adding the new setting.
            foreach(var entry in SettingsDictionary)
            {
                var setting = settingsSection.Elements().FirstOrDefault(e => e.Attribute(NAME).Value == entry.Key);
                if(setting == null) //this can happen if a new setting is added via the .settings designer.
                {
                    var newSetting = new XElement(SETTING);
                    newSetting.Add(new XAttribute(NAME, entry.Value.name));
                    newSetting.Add(new XAttribute(SERIALIZE_AS, entry.Value.serializeAs));
                    newSetting.Value = (entry.Value.value ?? String.Empty);
                    settingsSection.Add(newSetting);
                }
                else //update the value if it exists.
                {
                    setting.Value = (entry.Value.value ?? String.Empty);
                }
            }
            import.Save(UserConfigPath);
        }

        #region Angelo
        private object GetDefaultValue(SettingsProperty setting)
        {
            if (setting.PropertyType.IsEnum)
                return Enum.Parse(setting.PropertyType, setting.DefaultValue.ToString());

        // Return the default value if it is set
        // Return the default value if it is set
            if (setting.DefaultValue != null)
            {
                System.ComponentModel.TypeConverter tc = System.ComponentModel.TypeDescriptor.GetConverter(setting.PropertyType);
                return tc.ConvertFromString(setting.DefaultValue.ToString());
            }
            else // If there is no default value return the default object
            {
                return Activator.CreateInstance(setting.PropertyType);
            }
        }
        #endregion
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统配置;
运用系统反思;
使用System.Xml.Linq;
使用System.IO;
// ==>>>>  https://stackoverflow.com/questions/2265271/custom-path-of-the-user-config
// https://stackoverflow.com/questions/1947185/c-sharp-get-special-folder
名称空间MyApp.Interface
{
类CustomSettingsProvider:SettingsProvider
{
#区域辅助结构
/// 
///助手结构。
/// 
内部结构设置结构
{
内部字符串名称;
内部字符串序列化为;
内部字符串值;
} 
#端区
#区域常数
常量字符串NAME=“NAME”;
const string SERIALIZE_AS=“serializeAs”;
const string CONFIG=“配置”;
const string USER_SETTINGS=“userSettings”;
常量字符串设置=“设置”;
#端区
#区域字段
bool_加载;
#端区
#区域属性
/// 
///覆盖。
/// 
公共重写字符串ApplicationName{get{return System.Reflection.Assembly.GetExecutionGassembly().ManifestModule.Name;}集{/*不执行任何操作*/}
/// 
///在使用设置之前,必须设置返回的设置键。
///例如,Properties.Settings.Default.SettingsKey=@“C:\temp\user.config”;
/// 
私有字符串UserConfigPath
{
得到
{
System.Diagnostics.FileVersionInfo版本信息;
字符串strUserConfigPath,strUserConfigFolder;
strUserConfigPath=Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData,Environment.SpecialFolderOption.Create);
versionInfo=System.Diagnostics.FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location);
strUserConfigPath=Path.Combine(strUserConfigPath,versionInfo.CompanyName,versionInfo.ProductName,versionInfo.ProductVersion,“user.config”);
strUserConfigFolder=Path.GetDirectoryName(strUserConfigPath);
如果(!Directory.Exists(strUserConfigFolder))
CreateDirectory(strUserConfigFolder);
返回strusterconfigpath;
}
}
/// 
///设置值的内存存储
/// 
专用字典设置字典{get;set;}
#端区
#区域构造函数
/// 
///将文件加载到内存中。
/// 
公共自定义设置Provider()
{
SettingsDictionary=新字典();
} 
/// 
///覆盖。
/// 
public override void Initialize(字符串名称,System.Collections.Specialized.NameValueCollection配置)
{
初始化(ApplicationName,config);
}
#端区
/// 
///必须重写此项,这是将设计器属性与字典值匹配的位
/// 
/// 
/// 
/// 
公共覆盖设置PropertyValueCollection GetPropertyValues(设置上下文上下文,设置PropertyCollection集合)
{
//加载文件
如果(!\u已加载)
{
_加载=真;
LoadValuesFromFile();
}
//将返回的集合。
SettingsPropertyValueCollection值=新的SettingsPropertyValueCollection();
//迭代从设计器获得的属性,检查设置是否在字典中
foreach(集合中的设置属性设置)
{
SettingsPropertyValue值=新的SettingsPropertyValue(设置);
value.IsDirty=false;
//需要强类型的值的类型
var t=Type.GetType(setting.PropertyType.FullName);
if(SettingsDictionary.ContainsKey(setting.Name))
{
value.SerializedValue=SettingsDictionary[setting.Name].value;
value.PropertyValue=Convert.ChangeType(SettingsDictionary[setting.Name].value,t);
}
else//在没有设置的情况下使用默认值
{
value.SerializedValue=setting.DefaultValue;
value.PropertyValue=Convert.ChangeType(setting.DefaultValue,t);
}
增加(价值);
}
返回值;
}
/// 
///必须重写此项,这是在调用Settings.Save()时保存到file.Called的位
/// 
/// 
/// 
公共重写无效SetPropertyValue(SettingsContext上下文,SettingsPropertyValueCollection集合)
{
//从collection参数中获取值并更新字典中的值。
弗雷奇
var t = Type.GetType(setting.PropertyType.FullName);

if (SettingsDictionary.ContainsKey(setting.Name))
{
    value.SerializedValue = SettingsDictionary[setting.Name].value;
    // value.PropertyValue = Convert.ChangeType(SettingsDictionary[setting.Name].value, t);
    value.PropertyValue = getPropertyValue(SettingsDictionary[setting.Name].value, t, setting.SerializeAs);
}
else //use defaults in the case where there are no settings yet
{
    value.SerializedValue = setting.DefaultValue;
    //   value.PropertyValue = Convert.ChangeType(setting.DefaultValue, t);
    value.PropertyValue = getPropertyValue((string)setting.DefaultValue, t, setting.SerializeAs);
}
private object getPropertyValue(string settingValue, Type settingType, SettingsSerializeAs serializeAs)
{
    switch (serializeAs)
    {
        case SettingsSerializeAs.String:
            return settingValue;
        case SettingsSerializeAs.Xml:
            //for demo purposes, assumes this is your int array--otherwise do further checking to get the correct type
            XmlSerializer serializer = new XmlSerializer(typeof(int[]));
            return serializer.Deserialize(new StringReader(settingValue));
        //implement further types as required
        default:
            throw new NotImplementedException(string.Format("Settings deserialization as {0} is not implemented", serializeAs));
    }
}