C# IsDefined的问题

在.NET 4.0(当然也包括4.0以前的版本)下,用反射判断某个方法是否运用了自定义Attribute时,可以通过调用MethodInfo的IsDefined()方法进行确认。当然,IsDefined()方法事实上定义在MethodInfo的父类MemberInfo中,但它仅仅被定义为抽象方法,真正的实现是在MethodInfo的子类DynamicMethod中。调用方式如下所示:

代码如下:

methodInfo.IsDefined(typeof(MyAttribute), false)

然而,在实际开发中,我发现该方法有一个问题。如果获得MethodInfo的方式是通过加载程序集,然后利用反射方式获得的MethodInfo对象,即使该方法运用了自定义Attribute,返回的结果仍然是false。例如,我们将需要判断的方法所在的类定义到一个单独的Project中,并编译为单独的dll文件,然后,利用Assembly的LoadFile()方式获得程序集:

代码如下:

var assembly = Assembly.LoadFile(assemblyPath);
var types = assembly.GetExportedTypes();
types.ToList().ForEach(
  type =>
  {
      var flag =
          type.GetMethods().Where(methodInfo => !methodInfo.IsAbstract).Any(
              methodInfo => methodInfo.IsDefined(typeof(MyAttribute), false));
      Console.WriteLine("Flag of IsDefined is: {0}", flag);
  }
);

打印出来的值为false。

反之,如果不是通过加载程序集,而是直接通过typeof()获得的Type,并调用其下MethodInfo.IsDefined()方法,只要该方法被运用了指定的Attribute,返回的结果则为true。

分析原因,大约是获得Type的方式不同所造成的。Assembly类的GetExportedType()实现如下所示:

代码如下:

[SecuritySafeCritical]
public override Type[] GetExportedTypes()
{
    Type[] o = null;
    GetExportedTypes(this.GetNativeHandle(), JitHelpers.GetObjectHandleOnStack<Type[]>(ref o));
    return o;
}

注意,这里返回的Type[]事实上是通过引用方式传递给了JitHelpers的GetObjectHandleOnStack<Type[]>方法中:

代码如下:

[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), SecurityCritical]
internal static ObjectHandleOnStack GetObjectHandleOnStack<T>(ref T o) where T: class
{
    TypedReference reference = __makeref(o);
    return new ObjectHandleOnStack(reference.GetPointerOnStack());
}

这里将Type转换成了TypedReference。关键大约就是这里,可惜我无法找到typeof()的具体实现方式。代码追踪到这里,就无法判断这里发生的真实原因了。若要了解.NET底层机制的同学,可以告诉我。

若要解决反射方式无法通过IsDefined()判断的问题,可以调用MethodInfo的GetCustomAttribute()方法。例如:

代码如下:

private static bool IsAppliedWith(this MethodInfo methodInfo, Type attributeType, string attributeName)
{
    return methodInfo.GetCustomAttributes(attributeType, false).ToString().Contains(attributeName);
}

无论是利用反射加载,还是使用typeof,采用这种方式判断方法是否运用了指定的Attribute,都是能够生效的。

以上就是C#IsDefined的问题的全部内容,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • c++ 尽量不要使用#define 而是用const、enum、inline替换。

    例如:这里程序文件开头有如下#define语句 复制代码 代码如下: #define N 10 #define PI 3.14 #define MAX 10000 #define Heigth 6.65 ... ... 假设这里程序运行出错误,而且就是在我们使用这些常量有错误,此时编辑器应该会抛出错误信息.如果该信息提示6.65这里有错误,Ok如果你运气好你正好记得或者程序简单一眼能找到6.65表示什么,如果程序很复杂,而且报出6.65的文件是引用该文件,不记得,那么你会困惑这是什么?或许会花大

  • C#.NET学习笔记5 C#中的条件编译

    条件编译是C#比Java多出的东西,但我跟前辈请教后,他们都说条件编译在实际的项目开发中不怎么使用.鉴于是新内容,我还是做做笔记,理解一下好了. 条件编译属于编译预处理的范畴,它能让我们通过条件编译的机制,将部分代码包括进来或者排除出去,其作用与if-else类似.条件编译指令有以下四种

  • 简单记录C# 条件编译

    第一步:配置管理器中新建解决方案配置 第二步:定义条件编译符号: 第三步:在代码中使用自定义的条件编译 #if CustomDebug Console.WriteLine("dsads"); #endif 以上所述就是本文的全部内容了,希望大家能够喜欢

  • C# #define条件编译详解

    本文导读: C#的预处理器指令从来不会转化为可执行代码的命令,但是会影响编译过程的各个方面,常用的预处理器指令有#define.#undef.#if,#elif,#else和#endif等等,下面介绍C#中使用#define进行条件编译的实例. C#中条件编译指令用于按条件包含或排除源文件中的某些部分.在Visual Studio中,会看到被排除的代码显示为灰色. 一.#define可以用来做什么 1.当计划发布两个版本的代码的时候.即基本版和拥有更多版本的企业版,就可以用到条件编译指令: 2.

  • typedef和#define的用法以及区别

    一.typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像: typedef    int       INT;typedef    int       ARRAY[10];typedef   (int*)   pINT; typedef可以增强程序的可读性,以及标识符的灵活性,但它也有"非直观性"等缺点. 二.#define的用法 #define为一宏定义语句,通常用它来定义常量(包括无参

  • C语言中#define与typedef的互换细节详解

    复制代码 代码如下: #include <stdio.h>/*<---------           #define    string    char *            ---->*/typedef   char *   string; int main(void){   string   a[] = {"I", "like", "to", "fight,"},   b[] = {"

  • 详解C语言中的#define宏定义命令用法

    #define 命令#define定义了一个标识符及一个串.在源程序中每次遇到该标识符时,均以定义的串代换它.ANSI标准将标识符定义为宏名,将替换过程称为宏替换.命令的一般形式为: #define identifier string 注意: 1.该语句没有分号.在标识符和串之间可以有任意个空格,串一旦开始,仅由一新行结束. 2.宏名定义后,即可成为其它宏名定义中的一部分. 3.宏替换仅仅是以文本串代替宏标识符,前提是宏标识符必须独立的识别出来,否则不进行替换.例如: #define XYZ t

  • C语言编程技巧 关于const和#define的区别心得

    #define ASPECT_RATIO 1.653 编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中.如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO.如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去.这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不

  • 浅谈#ifndef,#define,#endif的作用和用法

    问题:ifndef/define/endif"主要目的是防止头文件的重复包含和编译 ======================================================== 用法: .h文件,如下: #ifndef XX_H #define XX_H ... #endif 这样如果有两个地方都包含这个头文件,就不会出现两次包含的情况 .. 因为在第二次包含时 XX_H 已经有定义了,所以就不再 include了 ------------------------------

  • C语言中的内联函数(inline)与宏定义(#define)详细解析

    先简明扼要,说下关键:1.内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快. 2.内联函数可以调试,而宏定义是不可以调试的.内联函数与宏本质上是两个不同的概念如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline.下面详细介绍一下探讨一下内联函数与宏定义. 一.内联函数是什么?内联函数是代码被插入到调用者代码处的函数.如同 #define 宏(但并不等同,原因见下文),内联函数通过避免被调用的开销来提

随机推荐