问题描述
提供以下课程:
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>
(我不希望跳过的属性为null).
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).
是否可以创建一个List<UiGridColumn>
,其中每个List
项目仅具有提供的值? (我担心这是不可能的,但我想我会问)如果可以,怎么办?
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"}]
我宁愿不遍历每个property
和attribute
和argument
来手动构建所需的JSON
字符串,但除此之外,我一直没有找到简单的方法.
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;
}
有更好的方法吗?
推荐答案
如果我正确理解了您的问题,您想序列化应用于类属性的属性列表吗?
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);
}
然后像这样使用它:
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"
}
]
您会注意到包含了来自基类Attribute
的TypeId
属性,并且属性名称也不是驼峰式的.要解决此问题,您需要使用自定义合同解析器:
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;
}
}
将解析程序添加到helper方法中的序列化设置中,您应该会很好:
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
};
现在输出应如下所示:
[
{
"name": "fullName",
"visible": false,
"width": "90"
},
{
"cellFilter": "date",
"name": "weekStart",
"visible": false
}
]
演示小提琴: https://dotnetfiddle.net/2R5Zyi
这篇关于序列化自定义属性值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!