c# - 在引用多个库时简化方法上的属性装饰器
问题描述
这是一个小小的不便,但最终会生成大量样板代码。我正在使用多个库(ServiceStack.Net、Json.Net、DataContractSerializer 等),并强制所有可能的解释器正确序列化/反序列化我的对象,我最终得到了许多如下所示的属性定义:
private const string select_comparisons = "select-comparisons";
[DataMember(Name = select_comparisons, EmitDefaultValue = true)]
[ApiMember(Name = select_comparisons)]
[JsonProperty(select_comparisons, DefaultValueHandling = DefaultValueHandling.Populate, NullValueHandling = NullValueHandling.Include)]
public bool SelectComparisons { get; set; }
这很烦人。最好编写如下内容:
[MyAttributeToRuleThemAll("select-comparisons", EmitDefaultValue = true, IgnoreNulls = true)]
public bool SelectComparisons { get; set; }
哪里MyAttributeToRuleThemAll
看起来像这样:
public class MyAttributeToRuleThemAll : Attribute, DataMember, ApiMember, JsonProperty
{
//insert attribute-specific logic in the constructor
}
我意识到建议的解决方案是不可能的,因为您不能以这种方式继承,但似乎应该有某种方法将公共属性简化为单个可重用组件。
更新:
我尝试使用以下代码从引用的副本中使用答案。
[TypeDescriptionProvider(typeof(SerializableTypeDescriptionProvider))]
public class SerializableTest
{
[Serializable("nu-id", DefaultValue = 2)]
public int Id { get; set; }
[Serializable("nu-key", DefaultValue = "2")]
public string Key { get; set; }
}
public interface IMetadatAttribute
{
Attribute[] Process();
}
public enum DefaultValueOptions
{
Include,
Exclude,
IncludeAndPopulate
}
public class SerializableAttribute : Attribute, IMetadatAttribute
{
public DefaultValueHandling DefaultValueHandling { get; set; }
public DefaultValueOptions DefaultValueOptions { get; set; }
public bool EmitDefaultValue { get; set; }
public bool IsRequired { get; set; }
public bool ExcludeInSchema { get; set; }
public bool AllowMultiple { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string DataType { get; set; }
public string Format { get; set; }
public string ParameterType { get; set; }
public string Route { get; set; }
public string Verb { get; set; }
public int Order { get; set; }
public object DefaultValue { get; set; }
public SerializableAttribute()
{
this.DefaultValueHandling = DefaultValueHandling.Include;
}
public SerializableAttribute(string name) : this()
{
Name = name;
}
public SerializableAttribute(string name, object defaultValue, bool emitDefaultValue, string description) : this(name)
{
DefaultValue = defaultValue;
EmitDefaultValue = emitDefaultValue;
Description = description;
}
public Attribute[] Process()
{
var attributes = new Attribute[]{
new DataMemberAttribute() {
EmitDefaultValue = EmitDefaultValue,
IsRequired = IsRequired,
Name = Name,
Order = Order },
new ApiMemberAttribute() {
Name = Name,
Description = Description,
ExcludeInSchema = ExcludeInSchema,
IsRequired = IsRequired,
AllowMultiple = AllowMultiple,
DataType = DataType,
Format = Format,
ParameterType = ParameterType,
Route = Route,
Verb = Verb
},
new JsonPropertyAttribute(Name) {
DefaultValueHandling = DefaultValueHandling,
PropertyName = Name,
NullValueHandling = NullValueHandling.Ignore,
ObjectCreationHandling = ObjectCreationHandling.Reuse
},
new DefaultValueAttribute(DefaultValue) {}
};
return attributes;
}
}
public class SerializableDescriptor : PropertyDescriptor
{
PropertyDescriptor original;
public SerializableDescriptor(PropertyDescriptor originalProperty)
: base(originalProperty) => original = originalProperty;
public override AttributeCollection Attributes
{
get
{
var attributes = base.Attributes.Cast<Attribute>();
var result = new List<Attribute>();
foreach (var item in attributes)
{
if (item is IMetadatAttribute)
{
var attrs = ((IMetadatAttribute)item).Process();
if (attrs != null)
{
foreach (var a in attrs)
result.Add(a);
}
}
else
result.Add(item);
}
return new AttributeCollection(result.ToArray());
}
}
public override Type ComponentType => original.ComponentType;
public override bool IsReadOnly => original.IsReadOnly;
public override Type PropertyType => original.PropertyType;
public override bool CanResetValue(object component) => original.CanResetValue(component);
public override object GetValue(object component)
{
return original.GetValue(component);
}
public override void ResetValue(object component) => original.ResetValue(component);
public override void SetValue(object component, object value) => original.SetValue(component, value);
public override bool ShouldSerializeValue(object component) => original.ShouldSerializeValue(component);
}
public class SerializableTypeDescriptor : CustomTypeDescriptor
{
ICustomTypeDescriptor original;
public SerializableTypeDescriptor(ICustomTypeDescriptor originalDescriptor)
: base(originalDescriptor) => original = originalDescriptor;
public override PropertyDescriptorCollection GetProperties() => GetProperties(new Attribute[] { });
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
.Select(p => new SerializableDescriptor(p))
.ToArray();
return new PropertyDescriptorCollection(properties);
}
}
public class SerializableTypeDescriptionProvider : TypeDescriptionProvider
{
public SerializableTypeDescriptionProvider()
: base(TypeDescriptor.GetProvider(typeof(object))) { }
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
object instance)
{
var baseDescriptor = base.GetTypeDescriptor(objectType, instance);
return new SerializableTypeDescriptor(baseDescriptor);
}
}
您可以执行以下操作:
void Main()
{
var nuTest = new SerializableTest();
var jsonOut = JsonConvert.SerializeObject(nuTest).Dump(); //or insert whatever ToJson/ToString logic here that you want
//expecting: { "nu-id": 2, "nu-key": "2" }
//getting: { "Id": 0, "Key": "null" }
}
虽然这编译和执行没有错误,但指定的属性没有按预期返回。手动注入[JsonProperty("nu-name")]
属性按预期工作。我假设这个属性方法是在编译时而不是在运行时生成的?
解决方案
推荐阅读
- hyperledger-fabric - 如何在 Fabric 2.0 中为多组织使用 PBFT
- android - 如何计算从相机到锚点的向量之间以及世界坐标中x轴之间的准确角度?
- javascript - 在同步批处理javascript中执行承诺
- mysql - PHP MYSQL 从数据库中返回最近 3 个月的日期 - Mysql Query
- python - 如何使用 JWT 身份验证在 rest_framework 中注销?
- typescript - 类型“HierarchyNode”上不存在属性“x”
' - javascript - gatsby-react-helmet 生成空
on SSR</h1> <div id="body"><p>My Gatsby website is not generating proper title tags on SSR. When I build the website all I get on my generated files are <code><title data-react-helmet="true">< - reactjs - 在测试反应应用程序期间,样式是“未定义”的
- linux - Bash“file --mime-type”命令在 Perl 脚本中不起作用
- java - 忽略 MS Access SELECT DISTINCTROW 中的某个列