1

一般的な設定クラスを作成する方法がわかりません。助けていただければ幸いです。
まず、単一の設定ファイル ソリューションが必要です。このために、次のようなシングルトンを作成しました。

public sealed class Settings
{
  private static readonly Lazy<Settings> _instance = new Lazy<Settings>(() => new Settings());
  private Dictionary<string, object> m_lProperties = new Dictionary<string, object>();

  public void Load(string fileName)
  {
    throw new NotImplementedException();  
  }

  public void Save(string fileName)
  {
    throw new NotImplementedException();
  }

  public void Update()
  {
    throw new NotImplementedException();
  }

  /// <summary>
  /// Gets the propery.
  /// </summary>
  /// <param name="propertyName">Name of the property.</param>
  /// <returns></returns>
  public string GetPropery(string propertyName)
  {
    return m_lProperties[propertyName].ToString() ?? String.Empty;
  }

  /// <summary>
  /// Gets the propery.
  /// </summary>
  /// <param name="propertyName">Name of the property.</param>
  /// <param name="defaultValue">The default value.</param>
  /// <returns></returns>
  public string GetPropery(string propertyName, string defaultValue)
  {
    if (m_lProperties.ContainsKey(propertyName))
    {
      return m_lProperties[propertyName].ToString();
    }
    else
    {
      SetProperty(propertyName, defaultValue);
      return defaultValue;
    }
  }

  /// <summary>
  /// Sets the property.
  /// </summary>
  /// <param name="propertyName">Name of the property.</param>
  /// <param name="value">The value.</param>
  public void SetProperty(string propertyName, string value)
  {
    if (m_lProperties.ContainsKey(propertyName))
      m_lProperties[propertyName] = value;
    else
      m_lProperties.Add(propertyName, value);
  }
}

しかし、より良い方法は、プロパティがクラスにあり、リフレクションを通じてプロパティを取得できることだと思います。
- このような実装を手伝ってもらえますか?
- 「encrypted = true」のようなプロパティ属性を与えることは可能ですか? - 設定をxmlファイルに保存/ロードする最良の方法は何ですか?

更新され
た実際の設定を使用する方法の例を次に示します。

class Test()
{
  private string applicationPath;
  private string configurationPath;
  private string configurationFile;

  public Test()
  {
    applicationPath = Settings.Instance.GetPropery("ApplicationPath", AppDomain.CurrentDomain.BaseDirectory);
    configurationPath = Settings.Instance.GetPropery("ConfigurationPath", "configurations");  
    configurationFile = Settings.Instance.GetPropery("ConfigurationFile", "application.xml");  
    // ... Load file with all settings from all classes
  } 
4

4 に答える 4

2

これは、私自身のコードからかなり関連性のあるビットです。

public class MyObject
{
    public string StringProperty {get; set;}

    public int IntProperty {get; set;}

    public object this[string PropertyName]
        {
            get
            {
                return GetType().GetProperty(PropertyName).GetGetMethod().Invoke(this, null);
            }
            set
            {
                GetType().GetProperty(PropertyName).GetSetMethod().Invoke(this, new object[] {value});
            }
        }
}

それが許すのは、これです:

MyObject X = new MyObject();
//Set
X["StringProperty"] = "The Answer Is: ";
X["IntProperty"] = 42;
//Get - Please note that object is the return type, so casting is required
int thingy1 = Convert.ToInt32(X["IntProperty"]);
string thingy2 = X["StringProperty"].ToString();

更新: 詳細説明これが機能する方法は、プロパティ に反射的にアクセスすることです。プロパティは、直接宣言してアクセスするのではなく、ゲッターとセッターを使用するという点でフィールドとは異なります。この同じメソッドを使用して、フィールドを取得したり、フィールドを取得したりできます。単純に機能すると仮定するのではなく、GetProperty からの戻り値を null チェックする場合です。また、別のコメントで指摘されたように、存在しないプロパティでそのまま呼び出すと、エラーをキャッチする形式がないため、これは壊れます。コードは、最も堅牢な形式ではなく、可能な限り単純な形式で示しました。

プロパティ属性に関する限り....そのインデクサーは、それを使用するクラス(または親クラス、私は my にありますBaseObject)内に作成する必要があるため、内部的に特定のプロパティに属性を実装してからスイッチを適用できますまたは、アクセス時にプロパティをチェックします。たぶん、すべてのプロパティを実装する他のカスタムクラスにObject Value; Bool Encrypted;して、そこから必要に応じて作業します。それは、どれだけファンシーになりたいか、どれだけのコードを書きたいかによって異なります。

于 2013-01-16T13:30:05.177 に答える
1

非常に遅いため、Reflection を使用しなくてもよい場所で使用することはお勧めしません。

リフレクションと暗号化プロトタイプのない私の例:

public sealed class Settings
{
    private static readonly HashSet<string> _propertiesForEncrypt = new HashSet<string>(new string[] { "StringProperty", "Password" });
    private static readonly Lazy<Settings> _instance = new Lazy<Settings>(() => new Settings());
    private Dictionary<string, object> m_lProperties = new Dictionary<string, object>();

    public void Load(string fileName)
    {
        // TODO: When you deserialize property which contains into "_propertiesForEncrypt" than Decrypt this property.
        throw new NotImplementedException();
    }

    public void Save(string fileName)
    {
        // TODO: When you serialize property which contains into "_propertiesForEncrypt" than Encrypt this property.
        throw new NotImplementedException();
    }

    public void Update()
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// Gets the propery.
    /// </summary>
    /// <param name="propertyName">Name of the property.</param>
    /// <returns></returns>
    public object GetPropery(string propertyName)
    {
        if (m_lProperties.ContainsKey(propertyName))
            return m_lProperties[propertyName];

        return null;
    }

    /// <summary>
    /// Gets the propery.
    /// </summary>
    /// <param name="propertyName">Name of the property.</param>
    /// <param name="defaultValue">The default value.</param>
    /// <returns></returns>
    public object GetPropery(string propertyName, object defaultValue)
    {
        if (m_lProperties.ContainsKey(propertyName))
        {
            return m_lProperties[propertyName].ToString();
        }
        else
        {
            SetProperty(propertyName, defaultValue);
            return defaultValue;
        }
    }

    /// <summary>
    /// Sets the property.
    /// </summary>
    /// <param name="propertyName">Name of the property.</param>
    /// <param name="value">The value.</param>
    public void SetProperty(string propertyName, object value)
    {
        if (m_lProperties.ContainsKey(propertyName))
            m_lProperties[propertyName] = value;
        else
            m_lProperties.Add(propertyName, value);
    }


    // Sample of string property
    public string StringProperty
    {
        get
        {
            return GetPropery("StringProperty") as string;
        }
        set
        {
            SetProperty("StringProperty", value);
        }
    }

    // Sample of int property
    public int IntProperty
    {
        get
        {
            object intValue = GetPropery("IntProperty");
            if (intValue == null)
                return 0; // Default value for this property.

            return (int)intValue;
        }
        set
        {
            SetProperty("IntProperty", value);
        }
    }
}
于 2013-01-16T13:54:44.753 に答える
0

最大の問題の 1 つは、オブジェクトをオブジェクトに逆シリアル化する明確な方法がないことです。オブジェクトの Type がどのようなものである必要があるかを前もって知らなければ、それを扱うのは非常に困難です。したがって、別の解決策として、型情報を保存します。

リストにないので、私が考える XML の例と、それを使用する方法、およびプロパティ自体にアクセスする方法を示します。Get および Set プロパティに使用している関数はそのまま機能し、変更する必要はありません。

個々のクラスでは、そのクラスの関連するプロパティが独自の get/set メソッドで Settings クラスを参照していることを確認する必要があります

public int? MyClassProperty
{
    get
    {
        return (int?)Settings.Instance.GetProperty("MyClassProperty");
    }
    set
    {
        Settings.Instance.SetProperty("MyClassProperty", value);
    }
}

ロードおよび保存関数では、シリアライゼーション、特にXmlSerializer. これを行うには、設定のリストを適切に宣言する必要があります。このために、実際にはカスタムクラスを使用します。

適切にロードできるように更新

public class AppSetting
{
    [XmlAttribute("Name")]
    public string Name { get; set; }
    [XmlAttribute("pType")]
    public string pType{ get; set; }
    [XmlIgnore()]
    public object Value{ get; set; }
    [XmlText()]
    public string AttributeValue 
    {
        get { return Value.ToString(); }
        set {
        //this is where you have to have a MESSY type switch
        switch(pType) 
        { case "System.String": Value = value; break;
          //not showing the whole thing, you get the idea
        }
    }
}

次に、単なる辞書の代わりに、次のようなものがあります。

public sealed class Settings
{
  private static readonly Lazy<Settings> _instance = new Lazy<Settings>(() => new Settings());
  private Dictionary<string, object> m_lProperties = new Dictionary<string, object>();
  private List<AppSetting> mySettings = new List<AppSetting>();

ロード関数は単純な逆シリアル化になります

public void Load(string fileName)
{//Note: the assumption is that the app settings XML will be defined BEFORE this is called, and be under the same name every time.
    XmlSerializer ser = new XmlSerializer(typeof(List<AppSetting>));
    FileStream fs = File.Open(fileName);
    StreamReader sr = new StreamReader(fs);
    mySettings = (List<AppSetting>)ser.DeSerialize(sr);
    sr.Close();
    fs.Close();

    //skipping the foreach loop that will add all the properties to the dictionary
}

保存機能は本質的にそれを逆にする必要があります。

public void Save(string fileName)
    {
        //skipping the foreach loop that re-builds the List from the Dictionary
        //Note: make sure when each AppSetting is created, you also set the pType field...use Value.GetType().ToString()

        XmlSerializer ser = new XmlSerializer(typeof(List<AppSetting>));
        FileStream fs = File.Open(fileName, FileMode.Create);
        StreamWriter sw = new StreamWriter(fs);
        //get rid of those pesky default namespaces
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");
        ser.Serialize(sw, mySettings, ns);
        sw.Flush();
        sw.Close();
        fs.Close();
        mySettings = null;//no need to keep it around
    }

xml は次のようになります。

更新しました

<ArrayOfAppSetting>
    <AppSetting Name="ApplicationPath" pType="System.String">C:\Users\ME\Documents\Visual Studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\</AppSetting> 
    <AppSetting Name="ConfigurationPath" pType="System.String">configurations</AppSetting> 
    <AppSetting Name="ConfigurationFile" pType="System.String">application.xml</AppSetting> 
    <AppSetting Name="prop" pType="System.Int32">1</AppSetting> 
</ArrayOfAppSetting>

List<>XmlSerializer で IDictionary を実装するものは何も使用できないことが判明したため、中間を使用してこの例を示しました。初期化に失敗し、機能しません。

辞書と一緒にリストを作成して維持するか、辞書をリストに置き換えることができます...「名前」が一意であることを確認するためのチェックがあることを確認するか、保存中以外は単にリストを無視できますロード操作 (この例を書いた方法です)

更新 これは実際にはプリミティブ型 (int、double、string など) でのみうまく機能しますが、型を直接格納するため、それが何であるか、およびそれをどうするかを知っているため、必要なカスタム型を使用できます。 、 AttributeValue の set メソッドで処理するだけです

別の更新:すべてのタイプのオブジェクトではなく、文字列のみを保存している場合...途方もなく簡単になります。XmlIgnore valueANDを取り除きpType、次に auto-implement を実行しAttributeValueます。ブーム、完了。ただし、文字列やその他のプリミティブに制限されますが、他のクラスの値の Get/Set がそれらを適切にキャストしていることを確認してください...しかし、それははるかに単純で簡単な実装です。

于 2013-01-16T15:08:43.230 に答える
0

https://gist.github.com/3914644のような動的クラスを使用して、yourObject.stringProperty または yourObject.intProperty としてプロパティにアクセスできるようにします。

于 2013-01-16T13:42:27.280 に答える