如何使用方法属性调用方法?

时间:2017-09-22 07:40:21

标签: c# .net

我在类中有多个方法实例,我需要快速调用和写入,而不将它们添加到我的main函数中。如何用属性完成?

e.g。 我有很多不同的类,有一个名为' invoke'的方法。我想添加一个我可以添加到此方法的自定义属性,然后在另一个名为' invoke all'的其他方法中调用每个类的invoke方法。

看起来像这样,但功能性。

public class main_class
{ 
   public void invoke_all()
   {
      // call all the invokes
   }

}

public class test1
{
   [invoke]
   public void invoke()
   {
      Console.WriteLine("test1 invoked");
   }
}
public class test2
{
   [invoke]
   public void invoke()
   { 
     Console.WriteLine("test2 invoked");
   }
}

6 个答案:

答案 0 :(得分:2)

要调用方法,您需要实例化一个类。要实例化类,您需要知道类型。

所以我们需要

  1. 查找包含标有Invoke属性
  2. 的方法的所有类
  3. 然后实例化那些类
  4. 调用所有标记的方法。
  5. 我们首先定义属性:

    public class InvokeAttribute : Attribute
    {
    }
    

    您可以使用此属性标记方法:

    public class TestClass1
    {
        [Invoke]
        public void Method1()
        {
            Console.WriteLine("TestClass1->Method1");
        }
        [Invoke]
        public void Method2()
        {
            Console.WriteLine("TestClass1->Method2"););
        }
    }
    
    public class TestClass2
    {
        [Invoke]
        public void Method1()
        {
            Console.WriteLine("TestClass2->Method1");
        }
    }
    

    现在如何找到并调用这些方法:

    var methods = AppDomain.CurrentDomain.GetAssemblies() // Returns all currenlty loaded assemblies
            .SelectMany(x => x.GetTypes()) // returns all types defined in this assemblies
            .Where(x => x.IsClass) // only yields classes
            .SelectMany(x => x.GetMethods()) // returns all methods defined in those classes
            .Where(x => x.GetCustomAttributes(typeof(InvokeAttribute), false).FirstOrDefault() != null); // returns only methods that have the InvokeAttribute
    
    foreach (var method in methods) // iterate through all found methods
    {
        var obj = Activator.CreateInstance(method.DeclaringType); // Instantiate the class
        method.Invoke(obj, null); // invoke the method
    }
    

    上面的代码段将检查所有已加载的程序集。 linq查询

    1. 选择所有类型并过滤所有类
    2. 然后读取这些类中定义的所有方法
    3. 并检查这些方法是否标有InvokeAttribute
    4. 这为我们提供了MethodInfo的列表。方法信息包含DeclaringType,它是声明方法的类。

      我们可以使用Activator.CreateInstance来实例化此类的对象。这仅在类具有不带参数的公共构造函数时才有效。

      然后我们可以使用MethodInfo在先前创建的类intance上调用该方法。这仅在方法没有参数时才有效。

答案 1 :(得分:1)

使用反射过程很简单:找到感兴趣的所有类型t,从类型m获取所有方法t,然后为每个m查找其自定义属性a,如果集合a包含您想要的属性,则调用该方法。

另见:

看起来像这样:

foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
    foreach (Type t in a.GetTypes())
    {
        // Skip types that don't have the [Invoke] attribute
        var typeContainsInvokeAttribute = t.GetCustomAttributes(typeof(InvokeAttribute)).Any();
        if (!typeContainsInvokeAttribute)
        {
            continue;
        }

        // This throws for types without a public, parameterless constructor
        var instance = Activator.CreateInstance(t);

        foreach (var methodInfo in instance.GetType().GetMethods())
        {
            var containsInvokeAttribute = methodInfo.GetCustomAttributes(typeof(InvokeAttribute)).Any();
            if (containsInvokeAttribute)
            {
                methodInfo.Invoke(instance);
            }

        }
    }
}

答案 2 :(得分:1)

您可以根据需要创建基于接口的解决方案。

我已经修改了你的代码并用这种方式实现了你想要的东西。

namespace ConsoleApplication1
{
    public class main_class
    {
        static void Main(string[] args)
        {
            main_class.invoke_all();
        }

        public static void invoke_all()
        {
            // call all the invokes
            // Help : https://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface

            foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype.GetInterfaces().Contains(typeof(IInvokeAll))))
            {
                mytype.GetMethod("invoke").Invoke(Activator.CreateInstance(mytype, null), null);
            }

            //wait for user input
            Console.ReadLine();
        }

    }

    interface IInvokeAll
    {
        void invoke();
    }

    public class test1 : IInvokeAll
    {
        //[invoke]
        public void invoke()
        {
            Console.WriteLine("test1 invoked");
        }
    }
    public class test2 : IInvokeAll
    {
        //[invoke]
        public void invoke()
        {
            Console.WriteLine("test2 invoked");
        }
    }
}

答案 3 :(得分:0)

对我来说有点不清楚,但我认为我有一个解决方案:

您无法直接执行您所要求的内容,但有解决方法 - 创建仅包含一种方法的界面:invoke(或更多,如您所愿),主要方法,创建实现接口的对象列表 - 或者只创建一个字段并在该方法中使用它。然后,在简单的foreach循环中,您可以对列表中的每个项目调用Invoke方法(这将是可能的,因为它们实现了与该方法的接口)。

答案 4 :(得分:0)

您可以使用静态事件而不是属性

>> compose [(a) (b) (c)]
== [1 2 3 4 5 6 7 8 9 10 ]

在类构造函数中订阅此事件

public static class Events
{
    public static event EventHandler OnInvoke;

    public static void Run()
    {
        OnInvoke?.Invoke(null, EventArgs.Empty);
    }
}

请勿忘记取消订阅此活动否则您的所有物品将永远不会被处置

这将在应用程序中的每个实例化(现有)对象上调用您的代码。表示如果您有两个public class Customer { public Customer() { Events.OnInvoke += (sender, args) => Call(); } } 类型的对象将比test1执行两次

答案 5 :(得分:-2)

这是一个示例代码,用于实现您希望使用委托的内容。

public class main_class
{
    private static main_class instance;

    public delegate void MethodInvoker();

    public MethodInvoker MyInvoker { get; set; }

    public static main_class Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new main_class();
            }

            return instance;
        }
    }

    private main_class() { }

    public void invoke_all()
    {
        MyInvoker();
    }

}

public class test1
{
    public test1()
    {
        main_class.Instance.MyInvoker += invoke;
    }
    public void invoke()
    {
        Console.WriteLine("test1 invoked");
    }
}
public class test2
{
    public test2()
    {
        main_class.Instance.MyInvoker += invoke;
    }
    public void invoke()
    {
        Console.WriteLine("test2 invoked");
    }
}

现在,只要你调用main_class.Instance.invoke_all();,它就会调用所有方法。