C# 如何获取应用了我的自定义属性的成员?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2168942/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I get the member to which my custom attribute was applied?
提问by Sarah Vessels
I'm creating a custom attributein C# and I want to do different things based on whether the attribute is applied to a method versus a property. At first I was going to do new StackTrace().GetFrame(1).GetMethod()
in my custom attribute constructor to see what method called the attribute constructor, but now I'm unsure what that will give me. What if the attribute was applied to a property? Would GetMethod()
return a MethodBase
instance for that property? Is there a different way of getting the member to which an attribute was applied in C#?
我正在C# 中创建一个自定义属性,我想根据该属性是应用于方法还是属性来做不同的事情。起初我打算new StackTrace().GetFrame(1).GetMethod()
在我的自定义属性构造函数中查看调用属性构造函数的方法,但现在我不确定这会给我带来什么。如果将该属性应用于属性会怎样?会GetMethod()
返回MethodBase
该属性的实例吗?是否有不同的方式来获取在 C# 中应用了属性的成员?
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = true)]
public class MyCustomAttribute : Attribute
Update:okay, I might have been asking the wrong question. From within a custom attribute class, how do I get the member (or the class containing the member) to which my custom attribute was applied? Aaronaughtsuggested against walking up the stack to find the class member to which my attribute was applied, but how else would I get this information from within the constructor of my attribute?
更新:好吧,我可能问错了问题。在自定义属性类中,如何获取应用了自定义属性的成员(或包含该成员的类)? Aaronaught建议不要在堆栈中查找应用我的属性的类成员,但是我如何从属性的构造函数中获取此信息?
采纳答案by Aaronaught
Since there seems to be a lot of confusion with respect to how the stack frames and methods work, here is a simple demonstration:
由于关于堆栈帧和方法的工作方式似乎有很多混淆,这里是一个简单的演示:
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;
}
}
}
The output of this program will be:
该程序的输出将是:
set_Name
设置名称
Properties in C# are a form of syntactic sugar. They compile down to getter and setter methods in the IL, and it's possible that some .NET languages might not even recognize them as properties - property resolution is done entirely by convention, there aren't really any rules in the IL spec.
C# 中的属性是一种语法糖。它们在 IL 中编译为 getter 和 setter 方法,并且有可能某些 .NET 语言甚至无法将它们识别为属性 - 属性解析完全按照约定完成,IL 规范中实际上没有任何规则。
Now, let's say for the moment that you had a really good reason for a program to want to examine its own stack (and there are precious fewpractical reasons to do so). Why in the world would you want it to behave differently for properties and methods?
现在,让我们暂时假设您有一个非常好的理由让程序想要检查自己的堆栈(而且这样做的实际理由很少)。为什么你希望它在属性和方法方面表现不同?
The whole rationale behind attributes is that they are a kind of metadata. If you want a different behaviour, code it into the attribute. If an attribute can mean two different things depending on whether it's applied to a method or property - then you should have two attributes. Set the target on the first to AttributeTargets.Method
and the second to AttributeTargets.Property
. Simple.
属性背后的全部原理是它们是一种元数据。如果您想要不同的行为,请将其编码到属性中。如果一个属性可以根据它是应用于方法还是属性而意味着两个不同的东西 - 那么你应该有两个属性。将第一个目标设置为AttributeTargets.Method
,将第二个目标设置为AttributeTargets.Property
。简单的。
But once again, walking your own stack to pick up some attributes from the calling method is dangerous at best. In a way, you are freezing your program's design, making it far more difficult for anybody to extend or refactor. This is not the way attributes are normally used. A more appropriateexample, would be something like a validation attribute:
但是再一次,遍历自己的堆栈以从调用方法中获取一些属性充其量是危险的。在某种程度上,您正在冻结程序的设计,使任何人都难以扩展或重构。这不是通常使用属性的方式。一个更合适的例子,类似于验证属性:
public class Customer
{
[Required]
public string Name { get; set; }
}
Then your validator code, which knows nothing about the actual entity being passed in, can do this:
然后,您的验证器代码(它对传入的实际实体一无所知)可以执行以下操作:
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);
}
}
}
In other words, you're examining the attributes of an instance that was given to youbut which you don't necessarily know anything about the type of. XML attributes, Data Contract attributes, even Attribute attributes - almost all attributes in the .NET Framework are used this way, to implement some functionality that is dynamic with respect to the type of an instancebut not with respect to the state of the programor what happens to be on the stack. It is very unlikely that you are actually in control of this at the point where you create the stack trace.
换句话说,您正在检查提供给您的实例的属性,但您不一定知道它的类型。XML 属性、数据协定属性,甚至 Attribute 属性 - .NET Framework 中的几乎所有属性都以这种方式使用,以实现一些与实例类型相关但与程序状态无关的动态功能或堆栈上会发生什么。在创建堆栈跟踪时,您实际上不太可能控制它。
So I'm going to recommend again that you don'tuse the stack-walking approach unless you have an extremely good reason to do so which you haven't told us about yet. Otherwise you are likely to find yourself in a world of hurt.
因此,我将再次建议您不要使用堆栈遍历方法,除非您有充分的理由这样做而您还没有告诉我们。否则你很可能会发现自己处于一个受伤的世界。
If you absolutely must (don't say we didn't warn you), then use two attributes, one that can apply to methods and one that can apply to properties. I think you'll find that to be much easier to work with than a single super-attribute.
如果你绝对必须(不要说我们没有警告你),那么使用两个属性,一个可以应用于方法,一个可以应用于属性。我想你会发现它比单个超级属性更容易使用。
回答by Amirshk
GetMethod
will always return you the function name. If it is a property, you will get either get_PropertyName
or set_PropertyName
.
GetMethod
将始终返回函数名称。如果它是一个属性,您将获得get_PropertyName
或set_PropertyName
。
A property is basically a type of method, so when you implement a property, the compiler creates two separate functions in the resulting MSIL, a get_ and a a set_ methods. This is why in the stack trace you receive these names.
属性基本上是一种方法,因此当您实现一个属性时,编译器会在生成的 MSIL 中创建两个单独的函数,即 get_ 和 aa set_ 方法。这就是为什么在堆栈跟踪中您会收到这些名称的原因。
回答by alexdej
custom attributes are activated by some code calling the GetCustomAttributes method on the ICustomAttributeProvider (reflection object) that represents the location where the attribute is applied. So in the case of a property, some code would obtain the PropertyInfo for the property and then call GetCustomAttributes on that.
自定义属性是通过调用 ICustomAttributeProvider(反射对象)上的 GetCustomAttributes 方法的一些代码激活的,该方法表示应用属性的位置。因此,在属性的情况下,某些代码将获取该属性的 PropertyInfo,然后对其调用 GetCustomAttributes。
If you want to build out some validation framework you would need to write the code that inspects types & members for custom attributes. You could for example have an interface that attributes implement to participate in your validation framework. Could be as simple as the following:
如果你想构建一些验证框架,你需要编写代码来检查自定义属性的类型和成员。例如,您可以拥有一个接口,该接口实现属性以参与您的验证框架。可以简单如下:
public interface ICustomValidationAttribute
{
void Attach(ICustomAttributeProvider foundOn);
}
Your code could look for this inteface on (for example) a Type:
您的代码可以在(例如)类型上查找此接口:
var validators = type.GetCustomAttributes(typeof(ICustomValidationAttribute), true);
foreach (ICustomValidationAttribute validator in validators)
{
validator.Attach(type);
}
(presumably you would walk the whole reflection graph and do this for each ICustomAttributeProvider). For an example of a similar approach in action in the .net FX you can look at WCF's 'behaviors' (IServiceBehavior, IOperationBehavior, etc).
(大概您会遍历整个反射图并为每个 ICustomAttributeProvider 执行此操作)。有关在 .net FX 中运行的类似方法的示例,您可以查看 WCF 的“行为”(IServiceBehavior、IOOperationBehavior 等)。
Update: the .net FX does have a sort-of general purpose, but basically undocumented interception framework in the form of ContextBoundObject and ContextAttribute. You can search the web for some examples of using it for AOP.
更新:.net FX 确实具有某种通用目的,但基本上是 ContextBoundObject 和 ContextAttribute 形式的未记录的拦截框架。您可以在网络上搜索一些将其用于 AOP 的示例。
回答by Scott Dorman
Attributes provide metadata and don't know anything about the thing (class, member, etc.) they are decorating. On the other hand, the thing being decorated can ask for the attributes it is decorated with.
属性提供元数据,但对它们所装饰的事物(类、成员等)一无所知。另一方面,被装饰的事物可以询问它被装饰的属性。
If you must know the type of the thing being decorated you will need to explicitly pass it to your attribute in its constructor.
如果您必须知道被装饰的事物的类型,则需要在其构造函数中将其显式传递给您的属性。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
Type type;
public MyCustomAttribute(Type type)
{
this.type = type;
}
}