Dav*_*New 40 .net c# reflection attributes custom-attributes
我创建了一个Attribute名为的类RelatedPropertyAttribute:
[AttributeUsage(AttributeTargets.Property)]
public class RelatedPropertyAttribute: Attribute
{
public string RelatedProperty { get; private set; }
public RelatedPropertyAttribute(string relatedProperty)
{
RelatedProperty = relatedProperty;
}
}
Run Code Online (Sandbox Code Playgroud)
我用它来表示类中的相关属性.我将如何使用它的示例:
public class MyClass
{
public int EmployeeID { get; set; }
[RelatedProperty("EmployeeID")]
public int EmployeeNumber { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我想使用lambda表达式,以便我可以将强类型传递给我的属性的构造函数,而不是"魔术字符串".这样我可以利用编译器类型检查.例如:
public class MyClass
{
public int EmployeeID { get; set; }
[RelatedProperty(x => x.EmployeeID)]
public int EmployeeNumber { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我以为我可以使用以下内容,但编译器不允许这样做:
public RelatedPropertyAttribute<TProperty>(Expression<Func<MyClass, TProperty>> propertyExpression)
{ ... }
Run Code Online (Sandbox Code Playgroud)
错误:
非泛型类型"RelatedPropertyAttribute"不能与类型参数一起使用
我怎样才能做到这一点?
cod*_*res 54
具有通用属性是不可能以传统方式进行的.但是C#和VB不支持它,但CLR支持它.如果你想写一些IL代码,那就有可能.
我们来看看你的代码:
[AttributeUsage(AttributeTargets.Property)]
public class RelatedPropertyAttribute: Attribute
{
public string RelatedProperty { get; private set; }
public RelatedPropertyAttribute(string relatedProperty)
{
RelatedProperty = relatedProperty;
}
}
Run Code Online (Sandbox Code Playgroud)
编译代码,开拓装配与ILSpy或ILDASM,然后倾倒内容到一个文本文件中.属性类声明的IL将如下所示:
.class public auto ansi beforefieldinit RelatedPropertyAttribute
extends [mscorlib]System.Attribute
Run Code Online (Sandbox Code Playgroud)
在文本文件中,您可以使该属性通用.有几件事需要改变.
这可以通过更改IL来完成,而CLR不会抱怨:
.class public abstract auto ansi beforefieldinit
RelatedPropertyAttribute`1<class T>
extends [mscorlib]System.Attribute
Run Code Online (Sandbox Code Playgroud)
现在您可以将relatedProperty的类型从字符串更改为通用类型.
例如:
.method public hidebysig specialname rtspecialname
instance void .ctor (
string relatedProperty
) cil managed
Run Code Online (Sandbox Code Playgroud)
将其更改为:
.method public hidebysig specialname rtspecialname
instance void .ctor (
!T relatedProperty
) cil managed
Run Code Online (Sandbox Code Playgroud)
有很多框架可以完成这样的"脏"工作:Mono.Cecil或CCI.
正如我已经说过的那样,它不是一个干净的面向对象的解决方案,而只是想指出另一种方法来打破C#和VB的限制.
围绕这个主题有一个有趣的阅读,请查看本书.
希望能帮助到你.
Mar*_*ell 33
你不能
[Foo<SomeType>])的语法Aym*_*man 13
如果您使用的是C#6.0,则可以使用nameof
用于获取变量,类型或成员的简单(非限定)字符串名称.在报告代码中的错误,连接模型 - 视图 - 控制器(MVC)链接,触发属性更改事件等时,通常需要捕获方法的字符串名称.使用nameof有助于在重命名定义时保持代码有效.之前必须使用字符串文字来引用定义,这在重命名代码元素时很脆弱,因为工具不知道检查这些字符串文字.
有了它,你可以像这样使用你的属性:
public class MyClass
{
public int EmployeeID { get; set; }
[RelatedProperty(nameof(EmployeeID))]
public int EmployeeNumber { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
一种可能的解决方法是为每个属性关系定义类,并通过
属性构造函数中的typeof()运算符引用它.
更新:
例如:
[AttributeUsage(AttributeTargets.Property)]
public class RelatedPropertyAttribute : Attribute
{
public Type RelatedProperty { get; private set; }
public RelatedPropertyAttribute(Type relatedProperty)
{
RelatedProperty = relatedProperty;
}
}
public class PropertyRelation<TOwner, TProperty>
{
private readonly Func<TOwner, TProperty> _propGetter;
public PropertyRelation(Func<TOwner, TProperty> propGetter)
{
_propGetter = propGetter;
}
public TProperty GetProperty(TOwner owner)
{
return _propGetter(owner);
}
}
public class MyClass
{
public int EmployeeId { get; set; }
[RelatedProperty(typeof(EmployeeIdRelation))]
public int EmployeeNumber { get; set; }
public class EmployeeIdRelation : PropertyRelation<MyClass, int>
{
public EmployeeIdRelation()
: base(@class => @class.EmployeeId)
{
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18670 次 |
| 最近记录: |