Sar*_*els 56 c# reflection attributes custom-errors
我在C#中创建了一个自定义属性,我希望根据属性是应用于方法还是属性来执行不同的操作.起初我打算new StackTrace().GetFrame(1).GetMethod()在我的自定义属性构造函数中查看调用属性构造函数的方法,但现在我不确定这会给我什么.如果属性应用于属性怎么办?会GetMethod()返回MethodBase该属性的实例吗?是否有不同的方法来获取在C#中应用属性的成员?
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = true)]
public class MyCustomAttribute : Attribute
Run Code Online (Sandbox Code Playgroud)
更新: 好吧,我可能一直在问错误的问题.在自定义属性类中,如何获取应用了自定义属性的成员(或包含成员的类)? Aaronaught建议不要走向堆栈以找到应用了我的属性的类成员,但是如何从属性的构造函数中获取此信息呢?
Aar*_*ght 41
由于堆栈框架和方法的工作方式似乎存在很多混淆,这里有一个简单的演示:
static void Main(string[] args)
{
MyClass c = new MyClass();
c.Name = "MyTest";
Console.ReadLine();
}
class MyClass
{
private string name;
void TestMethod()
{
StackTrace st = new StackTrace();
StackFrame currentFrame = st.GetFrame(1);
MethodBase method = currentFrame.GetMethod();
Console.WriteLine(method.Name);
}
public string Name
{
get { return name; }
set
{
TestMethod();
name = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
该计划的输出将是:
set_Name
C#中的属性是一种语法糖.他们在IL中编译为getter和setter方法,有些.NET语言可能甚至不会将它们识别为属性 - 属性解析完全按照惯例完成,IL规范中没有任何规则.
现在,让我们说一下,你有一个非常好的理由让一个程序想要检查它自己的堆栈(并且有很少的实际理由这样做).为什么在世界上你会希望它对属性和方法的表现不同?
属性背后的整个基本原理是它们是一种元数据.如果您想要不同的行为,请将其编码到属性中.如果一个属性可能意味着两个不同的东西,这取决于它是应用于方法还是属性 - 那么你应该有两个属性.将目标设置为第一个AttributeTargets.Method和第二个AttributeTargets.Property.简单.
但是再一次,走你自己的堆栈从调用方法中获取一些属性充其量是危险的.在某种程度上,你冻结了程序的设计,使得任何人扩展或重构都变得更加困难.这不是通常使用属性的方式.一个更合适的例子,就像验证属性:
public class Customer
{
[Required]
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后你的验证器代码,它对传入的实际实体一无所知,可以这样做:
public void Validate(object o)
{
Type t = o.GetType();
foreach (var prop in
t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (Attribute.IsDefined(prop, typeof(RequiredAttribute)))
{
object value = prop.GetValue(o, null);
if (value == null)
throw new RequiredFieldException(prop.Name);
}
}
}
Run Code Online (Sandbox Code Playgroud)
换句话说,您正在检查提供给您的实例的属性,但您不一定了解有关类型的实例.XML属性,数据协定属性,甚至属性属性 - .NET Framework中的几乎所有属性都以这种方式使用,以实现某些与实例类型相关的动态功能,但不涉及程序状态或什么发生在堆栈上.在创建堆栈跟踪时,您实际上无法控制此操作.
因此,我将再次建议您不要使用堆栈行走方法,除非您有充分的理由这样做,但您还没有告诉我们.否则你很可能会发现自己处于一个受伤的世界.
如果你绝对必须(不要说我们没有警告你),那么使用两个属性,一个可以应用于方法,一个可以应用于属性.我认为你会发现使用它比单个超级属性更容易.
Sco*_*man 40
属性提供元数据,并且不知道他们正在装饰的事物(类,成员等).另一方面,被装饰的东西可以要求它装饰的属性.
如果必须知道要装饰的东西的类型,则需要在构造函数中将其显式传递给属性.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
Type type;
public MyCustomAttribute(Type type)
{
this.type = type;
}
}
Run Code Online (Sandbox Code Playgroud)
GetMethod将始终返回函数名称。如果它是一个属性,您将获得get_PropertyName或set_PropertyName。
属性基本上是一种方法,因此当您实现一个属性时,编译器会在生成的 MSIL 中创建两个单独的函数,即 get_ 和 aa set_ 方法。这就是为什么在堆栈跟踪中您会收到这些名称的原因。
自定义属性由一些代码调用 ICustomAttributeProvider(反射对象)上的 GetCustomAttributes 方法来激活,该方法表示应用该属性的位置。因此,对于属性,某些代码将获取该属性的 PropertyInfo,然后对其调用 GetCustomAttributes。
如果您想构建一些验证框架,您需要编写检查类型和成员的自定义属性的代码。例如,您可以拥有一个属性实现的接口来参与您的验证框架。可以像下面这样简单:
public interface ICustomValidationAttribute
{
void Attach(ICustomAttributeProvider foundOn);
}
Run Code Online (Sandbox Code Playgroud)
您的代码可以在(例如)类型上查找此接口:
var validators = type.GetCustomAttributes(typeof(ICustomValidationAttribute), true);
foreach (ICustomValidationAttribute validator in validators)
{
validator.Attach(type);
}
Run Code Online (Sandbox Code Playgroud)
(大概您会遍历整个反射图并对每个 ICustomAttributeProvider 执行此操作)。有关 .net FX 中类似方法的示例,您可以查看 WCF 的“行为”(IServiceBehavior、IOperationBehavior 等)。
更新:.net FX 确实有一种通用的,但基本上是未记录的拦截框架,以 ContextBoundObject 和 ContextAttribute 的形式。您可以在网上搜索一些将其用于 AOP 的示例。
| 归档时间: |
|
| 查看次数: |
45930 次 |
| 最近记录: |