7

スキーマからC#クラス定義を書き込むコードジェネレーターでDefaultValue属性を使用しています。

スキーマのプロパティが文字列の配列であるところに行き詰まっています。

私のC#でこのようなものを書きたいです:

[DefaultValue(typeof(string[]), ["a","b"])]
public string[] Names{get;set;}

しかし、それはコンパイルされません。

文字列配列のデフォルト値属性を正常に宣言する方法はありますか?

4

2 に答える 2

11

あなたは試すことができます

[DefaultValue(new string[] { "a", "b" })]

新しい文字列配列を渡したいので、それをインスタンス化する必要があります-それはによって行われnew string[]ます。C#を使用すると、配列の初期内容を含む初期化リストを中かっこで囲むことができます{ "a", "b" }


編集: Cory-Gによって正しく指摘されているように、実際のインスタンスが属性に格納されている配列インスタンスを受け取らないようにする必要がある場合があります。そうしないと、そのインスタンスへの変更がアプリケーション全体のデフォルト値に影響を与える可能性があります。DefaultValue

代わりに、プロパティのセッターを使用して、割り当てられた配列をコピーできます。

于 2012-09-18T14:19:40.680 に答える
0

もう1つの解決策は、の仮想的な性質を利用してDefaultValueAttribute、独自の性質を引き出すことです。以下は、定数不可能なタイプの例です。

使用例:

public class Foo
{
    [DefaultValueNew( typeof(List<int>), new int[]{2,2} )]
    public List<int> SomeList { get; set; }

    // -- Or --
    public static List<int> GetDefaultSomeList2() => new List<int>{2,2};

    [DefaultValueCallStatic( typeof(Foo), nameof(GetDefaultSomeList2) )]
    public List<int> SomeList2 { get; set; }
};

これらの属性の定義は次のとおりです。

  public class DefaultValueNewAttribute : DefaultValueAttribute
  {
    public Type Type { get; }
    public object[] Args { get; }

    public DefaultValueNewAttribute(Type type, params object[] args)
      : base(null)
    {
      Type = type;
      Args = args;
    }

    public override object? Value => Activator.CreateInstance(Type, Args);
  };

  public class DefaultValueCallStaticAttribute : DefaultValueAttribute
  {
    public Type Type { get; }
    public string Method { get; }

    public DefaultValueCallStaticAttribute(Type type, string method)
      : base(null)
    {
      Type = type;
      Method = method;
    }

    public override object? Value => Type.GetMethod(Method, BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
  };

知っておくべき落とし穴

独自のを定義するときは注意してくださいDefaultValueAttribute。最も重要なことは、作成する前に、それがどのように使用されるかについて少し学ぶことです。コードジェネレーターのようなものの場合、上記はおそらく問題ありません。ただし、Newtonsoft Jsonや、ほとんどの場合値の比較にのみ使用するもので使用している場合は、時間を節約し、毎回オブジェクトを再作成しないようにするために、内部の値をより一定にする必要があります。

値が毎回再作成されないようにしたい状況では、次のようなことを行うことができます。

  public static readonly List<int> DefaultAges = new List<int>{2,2};
  private List<int> __ages = new List<int>(DefaultAges);
  [DefaultValueStatic( typeof(List<int>), nameof(DefaultAges) )]
  public List<int> Ages { get => __ages; set {__ages = new List<int>(value);}

属性DefaultValueStaticが次のように定義されている場合:

  public class DefaultValueStaticAttribute : DefaultValueAttribute
  {
    public DefaultValueStaticAttribute(Type type, string memberName) : base(null)
    {
      foreach (var member in type.GetMember( memberName, BindingFlags.Static | BindingFlags.Public ))
      {
        if (member is FieldInfo fi) { SetValue(fi.GetValue(type)); return; }
        if (member is PropertyInfo pi) { SetValue(pi.GetValue(type)); return; }
      }
      throw new ArgumentException($"Unable to get static member '{memberName}' from type '{type.Name}'");
    }
  };

上記のバージョンでは、デフォルト値が再作成されないことが保証されます。これは、セッターが頻繁に呼び出されないNewtonsoft jsonのようなもので役立ちますが、デフォルトの比較では呼び出されます。

繰り返しになりますが、属性がどのように使用されるかを少し知っていることを確認してください。

于 2021-07-24T22:01:22.093 に答える