如何在C#by attribute中搜索方法?

如何在C#by attribute中搜索方法?,c#,interface,attributes,C#,Interface,Attributes,我正在用C#为.NETCore编写一个命令行实用程序。我希望允许用户根据命令行参数指定要运行的“操作”。我在模仿PowerShell样式的命令行选项,因此我的选项之一是/Action。例如,用户可以使用/Action:Update或/Action:Reset调用应用程序 在C#中,我为每个操作提供了一个方法,该方法遵循特定的方法签名。因此,对于上面的Update方法,我有这样一个方法:publicstaticintupdate(Dictionary-cmdLineArgs,someobjecto

我正在用C#为.NETCore编写一个命令行实用程序。我希望允许用户根据命令行参数指定要运行的“操作”。我在模仿PowerShell样式的命令行选项,因此我的选项之一是
/Action
。例如,用户可以使用
/Action:Update
/Action:Reset
调用应用程序

在C#中,我为每个操作提供了一个方法,该方法遵循特定的方法签名。因此,对于上面的
Update
方法,我有这样一个方法:
publicstaticintupdate(Dictionary-cmdLineArgs,someobjectobj)
。与
/Action
上的有效参数相关的每个方法都具有完全相同的签名(相同的类型和变量名)

现在我只有一个
开关
块来调用操作,但这似乎效率极低:

int returnValue;
switch (parsedArgs["action"]) {
    case "update":
        returnValue = Update(parsedArgs, o);
        break;
    case "reset":
        returnValue = Reset(parsedArgs, o);
        break;
    ...
    default:
        returnValue=255;
        Console.WriteLine($"No such action {parsedArgs["action"]}.");
        break;
}
我在Web API的上下文中使用了属性,它们似乎是使其更通用的自然起点。理想情况下,添加一个新操作非常简单,只需编写其方法,并在
/action
开关中使用用户可以调用的名称添加正确的属性。我的想法是创建一个自定义属性(例如,
AppActionName
),然后将该属性放在任何可以从命令提示符作为操作调用的方法上:

[AppActionName("update")]
public static int Update(Dictionary<string,string> cmdLineArgs, SomeObject obj)
...

[AppActionName("reset")]
public static int Reset(Dictionary<string,string> cmdLineArgs, SomeObject obj)
...
第二个选项(类上的接口实现接口)似乎更安全,应该更容易实现(声明一个接口变量,然后将其分配给正确类的实例),但我仍然不确定如何实际搜索具有正确名称的属性

int returnValue;
// how would you do this correctly?
IAppAction appActionClass = new FindTheClassWithTheAttributeWithParameter("update")();
returnValue = appActionClass.Run(parsedArgs, o);

因此,我认为我的问题的实质是:“如何找到哪个方法/类具有我用指定参数定义的属性,然后如何实际实例化/调用结果?”

第二种方法通常更容易处理

我制作了一个示例(您可以运行),用于获取实现接口及其属性的类

考虑到这样的情况:

public class AppActionNameAttribute : Attribute 
{ 
    public string Action { get; set; } 

    public AppActionNameAttribute(string action) { Action = action; } 
}

public interface IAppAction 
{
    int Run(Dictionary<string,string> cmdLineArgs, SomeObject obj);
}

[AppActionName("update")]
public class UpdateAction : IAppAction
{
    public int Run(Dictionary<string,string> cmdLineArgs, SomeObject obj) 
    { 
        Console.WriteLine("Handled :)"); 
        return 1;
    }
}

public class SomeObject { }
private static Dictionary<string, IAppAction> _handlers = ...;

public static void Main()
{
    string action = Console.ReadLine();

    // you should check the action actually exists in the Dictionary
    var handler = _handlers[action];

    // and then run it:
    Console.WriteLine(handler.Run(someData, otherData));
}
公共类AppActionNameAttribute:Attribute
{ 
公共字符串操作{get;set;}
公共AppActionNameAttribute(字符串操作){action=action;}
}
公共接口IAppAction
{
int Run(Dictionary cmdLineArgs,SomeObject obj);
}
[AppActionName(“更新”)]
公共类更新操作:IAppAction
{
public int Run(字典cmdLineArgs,SomeObject obj)
{ 
Console.WriteLine(“已处理:)”;
返回1;
}
}
公共类SomeObject{}
您可以这样做:

var handlers = typeof(Program).Assembly
     // Get all types in the assembly
    .GetExportedTypes()
     // that are classes and implement IAppAction
    .Where(x => x.IsClass && x.GetInterface("IAppAction") != null)
    .Select(x => new 
    {
        // assuming they are always decorated with [AppActionName]
        Action = x.GetCustomAttribute<AppActionNameAttribute>().Action,
        // get a new instance, assuming parameterless constructor
        Handler = (IAppAction)Activator.CreateInstance(x)
    })
    // and convert it to a Dictionary that you can easily use
    .ToDictionary(x => x.Action, x => x.Handler);
var handlers=typeof(Program).Assembly
//获取程序集中的所有类型
.GetExportedTypes()
//它们是类并实现IAppAction
.Where(x=>x.IsClass&&x.GetInterface(“IAppAction”)!=null)
.选择(x=>new
{
//假设它们总是用[AppActionName]装饰
Action=x.GetCustomAttribute().Action,
//获取一个新实例,假设无参数构造函数
Handler=(IAppAction)Activator.CreateInstance(x)
})
//并将其转换为一本易于使用的词典
.ToDictionary(x=>x.Action,x=>x.Handler);
您可以将其存储(最好存储在某个静态字段中,因为您不希望经常运行此字段)并简单地使用如下:

public class AppActionNameAttribute : Attribute 
{ 
    public string Action { get; set; } 

    public AppActionNameAttribute(string action) { Action = action; } 
}

public interface IAppAction 
{
    int Run(Dictionary<string,string> cmdLineArgs, SomeObject obj);
}

[AppActionName("update")]
public class UpdateAction : IAppAction
{
    public int Run(Dictionary<string,string> cmdLineArgs, SomeObject obj) 
    { 
        Console.WriteLine("Handled :)"); 
        return 1;
    }
}

public class SomeObject { }
private static Dictionary<string, IAppAction> _handlers = ...;

public static void Main()
{
    string action = Console.ReadLine();

    // you should check the action actually exists in the Dictionary
    var handler = _handlers[action];

    // and then run it:
    Console.WriteLine(handler.Run(someData, otherData));
}
私有静态字典_handlers=。。。;
公共静态void Main()
{
string action=Console.ReadLine();
//您应该检查字典中实际存在的操作
var handler=_handlers[action];
//然后运行它:
WriteLine(handler.Run(someData,otherData));
}