如何通过自定义属性动态地计算所有方法 [英] How to figure out dynamically all methods with custom attribute

查看:179
本文介绍了如何通过自定义属性动态地计算所有方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的挑战。我动态地需要在C#中找出具体属性的所有方法。我将从另一个应用程序动态加载程序集,并且需要找出确切的方法。组件看起来如下:



Base.dll:

  Class Base 
{
[testmethod]
public void method1()
...
}

Derived.dll:

 派生类:Base 
{
[testmethod]
public void method2()
}

现在在第三个应用程序我动态喜欢加载上面提到的DLL,并找出测试方法。



如果我加载Base.dll,我需要得到testmethod1。如果我加载Drived.dll,我应该得到testmethod1和testmethod2。



我发现一些代码在线,帮助我动态加载dll:

 列表<装配> a = new List< Assembly>(); 

string bin = @Bin-Folder;

DirectoryInfo oDirectoryInfo = new DirectoryInfo(bin);

//检查目录是否存在
if(oDirectoryInfo.Exists)
{
// Foreach Assembly with dll作为扩展名
foreach(FileInfo oFileInfo在oDirectoryInfo.GetFiles(*。dll,SearchOption.AllDirectories))
{

Assembly tempAssembly = null;

//加载程序集之前,请检查所有当前加载的程序集,以防止已加载
//已经加载为另一个程序集的引用
//加载程序集两次可能会导致重大问题
foreach(Assembly LoadAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
//检查程序集是否动态生成,因为我们对这些
不感兴趣if(loadedAssembly.ManifestModule.GetType()。Namespace!=System.Reflection.Emit)
{
//获取加载的汇编文件名
string sLoadedFilename =
loadedAssembly。 CodeBase.Substring(loadedAssembly.CodeBase.LastIndexOf('/')+ 1);

//如果文件名匹配,则将程序集设置为已加载的程序集
if(sLoadedFilename.ToUpper()== oFileInfo.Name.ToUpper())
{
tempAssembly = loadedAssembly;
break;
}
}
}

//如果程序集不是aleady加载的,手动加载
if(tempAssembly == null)
{
tempAssembly = Assembly.LoadFrom(oFileInfo.FullName);
}
a.Add(tempAssembly);
}

上面的代码正常工作,我可以加载DLL。但是,当我使用以下代码找到正确的方法时,它不会返回任何所需的结果。我想知道哪一部分是不正确的。以下代码列出了大约145种方法,但不包括我们正在寻找的方法。

  public static List< string> GetTests(Type testClass)
{
MethodInfo [] methodInfos = testClass.GetType()。GetMethods(BindingFlags.Public | BindingFlags.Instance);
Array.Sort(methodInfos,
delegate(MethodInfo methodInfo1,MethodInfo methodInfo2)
{return methodInfo1.Name.CompareTo(methodInfo2.Name);});

foreach(MethodInfo mi in methodInfos)
{
foreach(var item in mi.GetCustomAttributes(false))
{
if
(item.ToString()。CompareTo(Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute)== 0)
result.Add(mi.Name);
}
}

返回结果;
}

有没有人可以帮我解决这个问题?



我不知道为什么,但是我试图从上面提到的类(Base和Derived)中实例化对象,并且上述代码返回正确的结果。但是如上所述,如果我没有从基类和派生类的对象,并尝试根据类型找出方法,它不会返回所需的结果。



Thx

解决方案

最简单的方法是使用 MethodInfo.IsDefined - 很可能还有LINQ:

  var testMethods =来自程序集中的程序集
来自assembly.GetTypes()中的类型
来自方法的
type.GetMethods()
其中method.IsDefined(typeof(TestMethodAttribute))
select方法;

foreach(testMethods中的var方法)
{
Console.WriteLine(method);
}

(我会用LINQ做所有的排序,显然你可以调整 GetMethods 调用等仅返回实例方法,例如。)



我不清楚为什么您当前的方法不起作用,或者为什么 在您创建实例时可以正常工作 - 但是如果没有简单但完整的示例来显示问题,则很难进一步诊断。我肯定从上面的代码开始:)


I have a simple challenge. I dynamically need to figure out all methods with a specific attribute in C#. I'm going to load the assemblies dynamically from another application and need to find out the exact methods. The assemblies look like the followings:

Base.dll:

 Class Base
   {
   [testmethod]
   public void method1()
   ... 
   }

Derived.dll:

 Class Derived:Base
  {
   [testmethod]
   public void method2()
  }

Now in 3rd application I dynamically like to load the above mentioned dlls and find out testmethods.

If I load Base.dll, I need to get testmethod1. If I load Drived.dll, should I get testmethod1 and testmethod2.

I found some code online which helped me to load dlls dynamically:

 List<Assembly> a = new List<Assembly>();

    string bin = @"Bin-Folder";

    DirectoryInfo oDirectoryInfo = new DirectoryInfo(bin);

    //Check the directory exists
    if (oDirectoryInfo.Exists)
    {
     //Foreach Assembly with dll as the extension
     foreach (FileInfo oFileInfo in oDirectoryInfo.GetFiles("*.dll", SearchOption.AllDirectories))
     {

      Assembly tempAssembly = null;

     //Before loading the assembly, check all current loaded assemblies in case talready loaded
    //has already been loaded as a reference to another assembly
    //Loading the assembly twice can cause major issues
    foreach (Assembly loadedAssembly in AppDomain.CurrentDomain.GetAssemblies())
    {
     //Check the assembly is not dynamically generated as we are not interested in these
     if (loadedAssembly.ManifestModule.GetType().Namespace != "System.Reflection.Emit")
     {
       //Get the loaded assembly filename
        string sLoadedFilename =
                                loadedAssembly.CodeBase.Substring(loadedAssembly.CodeBase.LastIndexOf('/') + 1);

      //If the filenames match, set the assembly to the one that is already loaded
        if (sLoadedFilename.ToUpper() == oFileInfo.Name.ToUpper())
        {
            tempAssembly = loadedAssembly;
            break;
        }
      }
     }

     //If the assembly is not aleady loaded, load it manually
     if (tempAssembly == null)
     {
         tempAssembly = Assembly.LoadFrom(oFileInfo.FullName);
     }
     a.Add(tempAssembly); 
    } 

The above code is working fine and I can load the DLLs. However when I use the following code to find out the right method, it doesn't return any desired results. I'm wondering which part is not correct. The following code lists about 145 methods but non of them is one which I'm looking for.

public static List<string> GetTests(Type testClass)
{
 MethodInfo[] methodInfos = testClass.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);
 Array.Sort(methodInfos,
       delegate(MethodInfo methodInfo1, MethodInfo methodInfo2)
 { return methodInfo1.Name.CompareTo(methodInfo2.Name); });

 foreach (MethodInfo mi in methodInfos)
 {
   foreach (var item in mi.GetCustomAttributes(false))
     {
      if
     (item.ToString().CompareTo("Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute") == 0)
                    result.Add(mi.Name);
            }
        }

        return result;
   }

Can any one help me with this issue?

I'm not sure why but I tried to instantiate objects from above mentioned classes (Base and Derived) and the above mentioned code returns the right results. However as mentioned above if I don't have an object from base and derived classes and try to figure out the methods based on the types, it doesn't return the desired results.

Thx

解决方案

The simplest approach is to use MethodInfo.IsDefined - quite possibly with LINQ as well:

var testMethods = from assembly in assemblies
                  from type in assembly.GetTypes()
                  from method in type.GetMethods()
                  where method.IsDefined(typeof(TestMethodAttribute))
                  select method;

foreach (var method in testMethods)
{
    Console.WriteLine(method);
}

(I'd do all the sorting with LINQ as well. Obviously you can tune the GetMethods call etc to only return instance methods, for example.)

It's not entirely clear to me why your current approach doesn't work or why it does work when you've created instances - but without a short but complete example demonstrating the problem, it would be hard to diagnose it further. I'd definitely start with the code above :)

这篇关于如何通过自定义属性动态地计算所有方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆