Смог подружить Settings.settings
с List<string>
<Setting Name="qq" Type="System.Collections.Generic.List<System.String>" Scope="User">
А реально такое провернуть с массивом ключ+значение? Пробовал с SortedDictionary
<Setting Name="ww" Type="System.Collections.Generic.SortedDictionary<System.String,System.String>" Scope="User">
И это даже заработало.. ненадолго.
После перезапуска приложения всё сбрасывается (естественно, перед закрытием всё сохранил), а в файле user.config
это выглядит так
<setting name="ww" serializeAs="Xml">
<value />
</setting>
А так же, не открывается окно Свойства - Параметры, с ошибкой типа "обнаружены непонятные символы". Очевидно, что он ругается на запятую
System.Collections.Generic.SortedDictionary<System.String,System.String>
Реально сохранить массив ключ+значение, или проще написать свою реализацию?
Можно, конечно, но с некоторыми заклинаниями.
Для начала, Settings
сериализируются XML-сериализатором. Поэтому так просто из коробки сохранить то, что XML-сериализатор не умеет, не удастася. В частности, и словарь.
Попробуйте выполнить код
new XmlSerializer(typeof(SortedDictionary<string, string>));
— вы получите исключение: The type SortedDictionary`2[System.String, System.String] is not supported because it implements IDictionary.
Поэтому придётся писать обёртку, которая будет сохранять данные в «плоском» списке, и умеет сконструировать нужный словать из этого.
public class DictionaryProxy<K, V>
{
public List<(K key, V value)> FlatList { get; set; }
[XmlIgnore]
public Dictionary<K, V> Dictionary
{
get => FlatList.ToDictionary(p => p.key, p => p.value);
set => FlatList = value.Select(kvp => (kvp.Key, kvp.Value)).ToList();
}
}
Далее нам понадобится трюк отсюда, чтобы заставить это взлететь. Положите в Settings
значение безодидного (например, строкового) типа с названием DictWrapper
, закройте Студию, и отредактируйте определение этого свойства Settings.settings
так:
<Setting Name="DictWrapper" Type="ТутВашНеймспейс.DictionaryProxy`2[System.String,System.String]" Scope="User">
<Value Profile="(Default)"><?xml version="1.0" encoding="utf-16"?>
<DictionaryProxyOfStringString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FlatList>
<ValueTupleOfStringString>
<Item1>k1</Item1>
<Item2>v1</Item2>
</ValueTupleOfStringString>
<ValueTupleOfStringString>
<Item1>k2</Item1>
<Item2>v2</Item2>
</ValueTupleOfStringString>
</FlatList>
</DictionaryProxyOfStringString>
</Value>
</Setting>
(О том, как получить ужасное значение для Value
, ниже.)
Далее, отредактируем и Settings.Designer.cs
, заменим определение свойства на такое:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute(@"<?xml version=""1.0"" encoding=""utf-16""?>
<DictionaryProxyOfStringString xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
<FlatList>
<ValueTupleOfStringString>
<Item1>k1</Item1>
<Item2>v1</Item2>
</ValueTupleOfStringString>
<ValueTupleOfStringString>
<Item1>k2</Item1>
<Item2>v2</Item2>
</ValueTupleOfStringString>
</FlatList>
</DictionaryProxyOfStringString>
")]
public global::ТутВашНеймспейс.DictionaryProxy<string, string> DictWrapper {
get {
return ((global::ТутВашНеймспейс.DictionaryProxy<string, string>)(this["DictWrapper"]));
}
set {
this["DictWrapper"] = value;
}
}
И можно пользоваться:
var dict = Properties.Settings.Default.DictWrapper.Dictionary;
Чтобы не набивать «вручную» текстовое представление сериализованного значения, можно использовать подготовительный код. Например, вот такой код
var o = new DictionaryProxy<string, string>();
o.Dictionary = new Dictionary<string, string>() { { "k1", "v1" }, { "k2", "v2" } };
var ss = new XmlSerializer(o.GetType());
using (var tw = new StringWriter())
{
ss.Serialize(tw, o);
var result = tw.GetStringBuilder().ToString();
}
производит в переменной result
значение
<?xml version="1.0" encoding="utf-16"?>
<DictionaryProxyOfStringString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FlatList>
<ValueTupleOfStringString>
<Item1>k1</Item1>
<Item2>v1</Item2>
</ValueTupleOfStringString>
<ValueTupleOfStringString>
<Item1>k2</Item1>
<Item2>v2</Item2>
</ValueTupleOfStringString>
</FlatList>
</DictionaryProxyOfStringString>
и вам остаётся лишь удвоить кавычки.
Чтобы заэкранировать знаки <
/>
, можно воспользоваться, например, таким кодом:
var xt = new XText(result);
var encodedResult = xt.ToString();
Получается вот что:
<?xml version="1.0" encoding="utf-16"?>
<DictionaryProxyOfStringString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FlatList>
<ValueTupleOfStringString>
<Item1>k1</Item1>
<Item2>v1</Item2>
</ValueTupleOfStringString>
<ValueTupleOfStringString>
<Item1>k2</Item1>
<Item2>v2</Item2>
</ValueTupleOfStringString>
</FlatList>
</DictionaryProxyOfStringString>
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
У меня есть две формы: FormStartMenu и Form15PuzzleМне нужно, чтобы при запуске приложения запускалась форма FormStartMenu, а потом из нее можно было бы перейти...
имеется программа которая с помощью CodeDom делает ещё одну программу, извините за тавтологиюВ c# для exe приложений можно создавать файл app
Чего хочу: получить данные с удалённого модуля по сокетуКак реализую: пока в одном потоке, чтобы проще было делать отладку