2016-10-24 11 views
1

は、以下のクラスに与えられた値:私は与えられた値と各フィールドのList<UiGridColumn>を作成したいシリアル化カスタム属性は

public class PayrollReport 
{ 
    [UiGridColumn(Name = "fullName",Visible = false,Width = "90")] 
    public string FullName { get; set; } 
    [UiGridColumn(Name = "weekStart", CellFilter = "date")] 
    public DateTime WeekStart { get; set; } 
} 

そして、このカスタム属性

[AttributeUsage(AttributeTargets.All)] 
public class UiGridColumn : Attribute 
{ 
    public string CellFilter { get; set; } 
    public string DisplayName { get; set; } 
    public string Name { get; set; } 
    public bool Visible { get; set; } 
    public string Width { get; set; } 
} 

を(私はしたくありませんスキップされたプロパティの場合はnull)。

Listの項目には指定された値のみが含まれていますが、List<UiGridColumn>を作成することはできますか? (私はこれが可能ではないことを恐れているが、私は尋ねると思った)もしそうなら、どのように?

ない場合は、私の第二の好みはこのような文字列の配列になります:私は手動で希望JSON文字列を構築するために、各propertyattributeargumentていないループを好むだろう

[{"name":"fullName","visible":false,"width":"90"},{"name":"weekStart","cellFilter":"date"}] 

が、私は避難所」そうでなければ簡単に行う方法を見つけることができました。

public List<Object> GetUiGridColumnDef(string className) 
{ 
    Assembly assembly = typeof(DynamicReportService).Assembly; 
    var type = assembly.GetType(className); 
    var properties = type.GetProperties(); 

    var columnDefs = new List<object>(); 
    foreach (var property in properties) 
    { 
     var column = new Dictionary<string, Object>(); 
     var attributes = property.CustomAttributes; 
     foreach (var attribute in attributes) 
     { 
      if (attribute.AttributeType.Name != typeof(UiGridColumn).Name || attribute.NamedArguments == null) 
        continue; 
      foreach (var argument in attribute.NamedArguments) 
      { 
       column.Add(argument.MemberName, argument.TypedValue.Value); 
      } 
     } 
     columnDefs.Add(column); 
    } 
    return columnDefs; 
} 

これを行うより良い方法はありますか?

答えて

1

あなたの質問が正しく理解できたら、クラスのプロパティに適用されている属性のリストをシリアル化したいのですか?

もしそうなら、あなたはこのようにそれを行うためにヘルパーメソッドを作ることができます:あなたはかなりある、この出力に終わるでしょう

string json = SerializeAppliedPropertyAttributes<UiGridColumn>(typeof(PayrollReport)); 

public static string SerializeAppliedPropertyAttributes<T>(Type targetClass) where T : Attribute 
{ 
    var attributes = targetClass.GetProperties() 
           .SelectMany(p => p.GetCustomAttributes<T>()) 
           .ToList(); 

    JsonSerializerSettings settings = new JsonSerializerSettings 
    { 
     NullValueHandling = NullValueHandling.Ignore, 
     Formatting = Formatting.Indented 
    }; 

    return JsonConvert.SerializeObject(attributes, settings); 
} 

次に、このようにそれを使用します

[ 
    { 
    "Name": "fullName", 
    "Visible": false, 
    "Width": "90", 
    "TypeId": "UiGridColumn, JsonTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 
    }, 
    { 
    "CellFilter": "date", 
    "Name": "weekStart", 
    "Visible": false, 
    "TypeId": "UiGridColumn, JsonTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 
    } 
] 

あなたがからTypeIdプロパティに気付くでしょう:あなたが探しているものに近いですbase Attributeクラスが含まれており、プロパティ名はラクダのケースではありません。ヘルパーメソッドでシリアライズの設定にリゾルバを追加し、あなたが行くために良いことがあり

public class SuppressAttributeTypeIdResolver : CamelCasePropertyNamesContractResolver 
{ 
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     JsonProperty prop = base.CreateProperty(member, memberSerialization); 
     if (member.DeclaringType == typeof(Attribute) && member.Name == "TypeId") 
     { 
      prop.ShouldSerialize = obj => false; 
     } 
     return prop; 
    } 
} 

JsonSerializerSettings settings = new JsonSerializerSettings 
    { 
     NullValueHandling = NullValueHandling.Ignore, 
     ContractResolver = new SuppressAttributeTypeIdResolver(), 
     Formatting = Formatting.Indented 
    }; 

それを修正するには、カスタム契約リゾルバを使用する必要があります出力は次のようになります。

[ 
    { 
    "name": "fullName", 
    "visible": false, 
    "width": "90" 
    }, 
    { 
    "cellFilter": "date", 
    "name": "weekStart", 
    "visible": false 
    } 
] 

デモフィドル:https://dotnetfiddle.net/2R5Zyi

+0

これはほぼ完璧です。 'Visible'は1つのプロパティに対してのみ定義されていましたが、' bool'であるため両方に表示されます。それを 'nullable'にしようとすると' Visible 'は有効な属性パラメータ型ではないため、有効な名前付き属性引数ではありません。提案? – davids

+0

'DefaultValueHandling = DefaultValueHandling.Ignore'を設定で使用して、' false'のデフォルト値に設定されているときに 'Visible'を抑制することができます。しかし、それは明示的にfalseに設定した最初のオブジェクトに対してもこれを抑止します。残念なことに、このソリューションでは、両方の方法を使用することはできません。常に値を含めるか、デフォルトと異なる場合にのみ値を含めるかのどちらかです。 –

+0

お役立ち情報私はデフォルト値をスキップして大丈夫です。しかし、デフォルトでは 'Visible'を' true'にしたいので、デフォルト値を変更して 'DefaultValueHandling'コードを追加しました。期待どおりに動作します。ありがとう! – davids

関連する問題