2016-10-24 39 views
1

考虑下面的类:序列化自定义属性值

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; } 
} 

我想创建一个只提供的值每个字段List<UiGridColumn>(我不想被跳过的属性为空)。

是否可以创建一个List<UiGridColumn>其中每个List项目只有提供的值? (我担心这是不可能的,但我想我会问)如果是这样,怎么样?

如果不,我的第二偏好将是一个字符串数组是这样的:

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

我宁愿通过每个propertyattributeargument不循环手动构建所需JSON串,但还没否则能够找到一个简单的方法来做到这一点。

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

如果我正确理解你的问题,你想序列化属性列表应用到类的属性?

如果是这样,你可以做一个辅助方法来做到这一点是这样的:

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); 
} 

然后使用它是这样的:

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

您将结束与该输出,这是相当接近你要找的东西:

[ 
    { 
    "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财产从包含基类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'不是有效的命名属性参数,因为它不是有效的属性参数类型'。建议? – davids

+0

当设置为默认值false时,可以在设置中使用DefaultValueHandling = DefaultValueHandling.Ignore来压制Visible。但是,这也将抑制第一个对象,你明确地将其设置为false。不幸的是,对于这种解决方案,您无法同时拥有这两种方法 - 要么始终包含该值,要么只有在与默认值不同时才包含该值。 –

+0

很高兴知道。我可以跳过默认值。不过,我希望'Visible'默认为'true',所以我改变了默认值并添加了'DefaultValueHandling'代码。它完全按预期工作。谢谢! – davids

相关问题