アプリケーション設定にint []配列を保存する方法


93

私はC#express 2008を使用して単純なWindowsフォームアプリケーションを作成しています。私は経験豊富なC ++開発者ですが、C#と.NETはまったく新しいものです。

現在、次のような設定デザイナーとコードを使用して、簡単なアプリケーション設定の一部を保存しています。

// Store setting  
Properties.Settings.Default.TargetLocation = txtLocation.Text;  
...  
// Restore setting  
txtLocation.Text = Properties.Settings.Default.TargetLocation;  

次に、intの配列(int[])、またはおそらくintsのリスト()のいずれかをList< int >設定として保存します。しかし、これを行う方法がわかりません。ドキュメント、stackoverflow、googleを検索しましたが、これを行う方法についての適切な説明が見つかりません。

私が見つけたまばらな例に基づく私の直感は、配列またはリストをラップするシリアル化可能なクラスを作成する必要があることです。それから、設定デザイナーでそのタイプを使用できるようになります。ただし、これをどのように行うかは正確にはわかりません。

回答:


136

別の解決策もあります-設定ファイルを少し手動で編集する必要がありますが、その後VS環境とコードで正常に動作します。また、追加の関数やラッパーは必要ありません。

重要なのは、VSがint[]設定ファイルでデフォルトでタイプをシリアル化できることです。デフォルトではそれを選択できません。そのため、目的の名前(例:SomeTestSetting)で設定を作成し、任意のタイプ(例:stringデフォルト)にします。変更を保存します。

次に、プロジェクトフォルダーに移動し、テキストエディター(メモ帳など)を使用して "Properties \ Settings.settings"ファイルを開きます。または、ソリューションエクスプローラーで "->プロパティ-> Settings.settingsを右クリックして、VSで開くこともできます。 "、[プログラムから開く...]を選択し、[XMLエディター]または[ソースコード(テキスト)エディター]を選択します。開いたxml設定で設定を見つけます(次のようになります):

<Setting Name="SomeTestSetting" Type="System.String" Scope="User">
  <Value Profile="(Default)" />
</Setting>

「タイプ」パラメータをからSystem.Stringに変更しSystem.Int32[]ます。このセクションは次のようになります。

<Setting Name="SomeTestSetting" Type="System.Int32[]" Scope="User">
  <Value Profile="(Default)" />
</Setting>

変更を保存してプロジェクト設定を再度開きます-ほら!-VS System.Int32[]設定デザイナ(値も)を介して、およびコードでアクセスおよび編集できるタイプの設定SomeTestSetting があります。


5
驚くばかり。Visual Studioのエディターを使用して設定に何かを入力するには、次のようなものを貼り付ける必要があります。これは文字列配列用であり、これが<?xml version = "1.0" encoding = "utf-16"?> <ArrayOfStringに必要でした。 xmlns:xsi = " w3.org/2001/XMLSchema-instance " xmlns:xsd = " w3.org/2001/XMLSchema "> <string> String1 </ string> <string> String2 </ string> </ ArrayOfString>
カルステン

9
+1 ..なぜこれが受け入れられなかったのかわからない..追加のコードは不要(既存のxmlの1行を変更するだけ)で、型の安全性と完全対デザイナーのサポートが得られます!
クリス、

1
クリス、ありがとう:)問題は、最初に受け入れられた回答よりもはるかに遅く回答を追加したことです(約1年後、実際には:))。でも経験を共有するだけです:)
Jen-Ari

6
好奇心旺盛な方のために、設定ファイルのXML構文int[]は次のようになります(かなりきれいに印刷されている場合を除く):<setting name="SomeTestSetting" serializeAs="String"><value><ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><int>1</int><int>2</int><int>3</int></ArrayOfInt></value></setting>
aaaantoine

1
同意しました、これはより良い答えなので、マークを変更しました。
sidewinderguy 2015年

40

保存する:

string value = String.Join(",", intArray.Select(i => i.ToString()).ToArray());

再作成するには:

int[] arr = value.Split(',').Select(s => Int32.Parse(s)).ToArray();

編集:アベル提案!


これで、データを手動で文字列にシリアル化しているように見えます。逆も同様です。これはうまくいくと思いますが、データを文字列設定として保存するだけで済みます。私はこのようなことをすることを考えましたが、私はもっと「クリーン」または「標準」またはもっともっと.NETっぽいものを探していました。ただし、これよりもうまくいくものがなければ、これを覚えておきます。ありがとう。
sidewinderguy

こんにちは、私はマッケイの大通りに行きます!(構成セクション/セクショングループ)
マイクグリーソンjr Couturier

簡単なのでこれでいきます。皆さんのアイデアに感謝します。彼らが将来のお手伝いをすると確信しています。
sidewinderguy

2
注:System.Linq上記のトリックを機能させるには、使用/インポートに追加する必要があります。
Sean Hanley、2010

11

この結果を達成する方法は他にもありますが、使用方法はかなりクリーンですが、より多くのコードが必要です。カスタムタイプとタイプコンバーターを実装すると、次のコードが可能になります。

List<int> array = Settings.Default.Testing;
array.Add(new Random().Next(10000));
Settings.Default.Testing = array;
Settings.Default.Save();

これを実現するには、文字列との間の変換を可能にする型コンバーターを備えた型が必要です。これを行うには、TypeConverterAttributeで型を装飾します。

[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray ...

次に、この型コンバーターをTypeConverterの派生として実装します。

class MyNumberArrayConverter : TypeConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext ctx, Type type)
    { return (type == typeof(string)); }

    public override bool CanConvertFrom(ITypeDescriptorContext ctx, Type type)
    { return (type == typeof(string)); }

    public override object ConvertTo(ITypeDescriptorContext ctx, CultureInfo ci, object value, Type type)
    {
        MyNumberArray arr = value as MyNumberArray;
        StringBuilder sb = new StringBuilder();
        foreach (int i in arr)
            sb.Append(i).Append(',');
        return sb.ToString(0, Math.Max(0, sb.Length - 1));
    }

    public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
    {
        List<int> arr = new List<int>();
        if (data != null)
        {
            foreach (string txt in data.ToString().Split(','))
                arr.Add(int.Parse(txt));
        }
        return new MyNumberArray(arr);
    }
}

MyNumberArrayクラスにいくつかの便利なメソッドを提供することで、Listとの間で安全に割り当てることができ、完全なクラスは次のようになります。

[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray : IEnumerable<int>
{
    List<int> _values;

    public MyNumberArray() { _values = new List<int>(); }
    public MyNumberArray(IEnumerable<int> values) { _values = new List<int>(values); }

    public static implicit operator List<int>(MyNumberArray arr)
    { return new List<int>(arr._values); }
    public static implicit operator MyNumberArray(List<int> values)
    { return new MyNumberArray(values); }

    public IEnumerator<int> GetEnumerator()
    { return _values.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator()
    { return ((IEnumerable)_values).GetEnumerator(); }
}

最後に、これを設定で使用するには、上記のクラスをアセンブリに追加してコンパイルします。Settings.settingsエディターで、[参照]オプションをクリックし、MyNumberArrayクラスを選択するだけです。

繰り返しますが、これははるかに多くのコードです。ただし、単純な配列よりもはるかに複雑なタイプのデータに適用できます。


ありがとうございます。機会があったらやってみます。
sidewinderguy

3

設定をSystem.Collections.ArrayListとして指定し、次のようにします。

Settings.Default.IntArray = new ArrayList(new int[] { 1, 2 });

int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));

2

簡単な解決策は、プロパティの設定のデフォルト値をnullに設定することですが、コンストラクターでプロパティがnullかどうかを確認し、nullの場合は実際のデフォルト値に設定します。したがって、intの配列が必要な場合:

public class ApplicationSettings : ApplicationSettingsBase
{
    public ApplicationSettings()
    {
        if( this.SomeIntArray == null )
            this.SomeIntArray = new int[] {1,2,3,4,5,6};
    }

    [UserScopedSetting()]
    [DefaultSettingValue("")]
    public int[] SomeIntArray
    {
        get
        {
            return (int[])this["SomeIntArray"];
        }
        set
        {
            this["SomeIntArray"] = (int[])value;
        }
    }
}

それは一種のハックに感じますが、コンストラクターが呼び出される前にプロパティが最後の(またはデフォルトの)設定に初期化されるため、見た目はきれいで、期待どおりに機能します。


2
アプリケーション設定ファイルのデザイナはコードを自動生成するため、このような変更は、誰かがデザイナを使用した場合でも、偶然であっても上書きされます。
カールG

1

中古System.Object

例:

byte[] arBytes = new byte[] { 10, 20, 30 };
Properties.Settings.Default.KeyObject = arBytes;

エキス:

arBytes = (byte[])Properties.Settings.Default.KeyObject;

1
System.Objectを使用してみましたが、セッション間で設定が保持されませんでした。(はい、それはリリースビルドであり、スタンドアロンインストールであり、なんといっても、IDEを使用してデバッグしていませんでした)
EmanuelVintilăMar


0

文字列のint配列を変換する関数をいくつか作成しますが、各関数の間に ""(スペース)のような文字を挿入します。

したがって、配列が{1,34,546,56}の場合、文字列は "1 34 645 56"になります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.