Serialize Custom Attribute Values

不想你离开。 提交于 2019-12-11 06:55:23

问题


Given the following class:

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

And this custom attribute

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

I want to create a List<UiGridColumn> for each field with only the provided values (I don't want a null for the skipped properties).

Is it possible to create a List<UiGridColumn> where each List item has only the provided values? (I fear this isn't possible, but thought I would ask) If so, how?

If not, my second preference would be a string array like this:

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

I would prefer to not loop through each property and attribute and argument to manually build the desired JSON string, but I haven't been able to find an easy way to do it otherwise.

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

Is there a better way to do this?


回答1:


If I understand your question correctly, you want to serialize the list of attributes applied to the properties on a class?

If so, you can make a helper method to do it like this:

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

Then use it like this:

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

You will end up with this output, which is pretty close to what you're looking for:

[
  {
    "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"
  }
]

You'll notice the TypeId property from the base Attribute class is included, and also the property names are not camel cased. To fix that, you'll need to use a custom contract resolver:

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

Add the resolver to the serialization settings in the helper method and you should be good to go:

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

Now the output should look like this:

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

Demo fiddle: https://dotnetfiddle.net/2R5Zyi



来源:https://stackoverflow.com/questions/40211364/serialize-custom-attribute-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!