将单个方法到多个字符串的Dictionary映射到单个字符串到多个方法的Dictionary

时间:2017-05-09 02:52:50

标签: c# linq reflection

我敢说这是我曾经想过的最复杂的头衔。 我只是不确定如何更好地解释它,缺少这个例子:

我有一个类型。在这种类型下,我有各种方法,其中一些方法附加了一个或多个“OnAttribute”属性,每个方法都定义了此方法需要触发的事件名称。我目前正在使用此查询获取方法词典到相关的事件名称列表:

var methods = this.GetType().GetMethods()
    .Where(m => Attribute.IsDefined(m, typeof(OnAttribute)))
    .ToDictionary(m => m,
        m => m.GetCustomAttributes(typeof(OnAttribute), true)
            .Select(a => ((OnAttribute)a).EventName)); //OnAttribute defines an EventName field

结果类型为IEnumerable<IGrouping<System.Reflection.MethodInfo,IEnumerable<string>>>。但是,为了为其请求的事件签署方法,我需要将每个事件名称映射到要求在其上执行的任何和所有方法。换句话说,我需要将前面提到的类型映射到IEnumerable<IGrouping<string,IEnumerable<System.Reflection.MethodInfo>>>

我需要这个:

[On("Event_1")]
[On("Event_2")]
[On("Event_4")]
void Method_1()
{
    ...
}

[On("Event_1")]
void Method_2()
{
     ...
}

[On("Event_2")]
[On("Event_3")]
void Method_3()
{
    ...
}

使用我当前的代码,将映射到:

Method_1 => ["Event_1","Event_2","Event_4"]
Method_2 => ["Event_1"]
Method_3 => ["Event_2","Event_3"]

而是映射到这个:

"Event_1" => [Method_1,Method_2]
"Event_2" => [Method_1,Method_3]
"Event_3" => [Method_2]
"Event_4" => [Method_1]

我确信有一些更好的术语来描述这个;我只是不知道它是什么。

我尝试使用foreach循环以丑陋的方式创建字典,但正如我所说,真的丑陋。我还尝试使用一些匿名类型的SelectMany()将Dictionary压缩成一个列表,然后使用GroupBy将该列表重新分组到我想要的字典中,但这似乎效率低下且杂乱无章。我想知道(最好的)LINQ方式。

我希望至少有一点意义。

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

您必须使用GroupByvar methods = this.GetType().GetMethods() .Where(m => Attribute.IsDefined(m, typeof(OnAttribute))) .SelectMany(m => m.GetCustomAttributes(typeof(OnAttribute), true) .Select(a => new { EventName = ((OnAttribute)a).EventName, MethodInfo = m })) .GroupBy(g => g.EventName, g => g.MethodInfo); 的组合来获得所需的结果。

这是一个似乎有效的解决方案:

EventName

在此解决方案中,首先展开集合以获取包含MethodInfoEventName的匿名类型的中间集合。这个匿名类型的中间集合,然后由EventName分组,以便{{1}}获取方法组。

答案 1 :(得分:0)

要从当前的方法字典中获取反向映射,可以执行以下操作:

var reverseMapping = methods
    .SelectMany(kvp => kvp.Value, (kvp, evt) => new { Event = evt, Method = kvp.Key })
    .GroupBy(a => a.Event, a => a.Method);

然后,如果你想把它们抛弃:

foreach (var grouping in reverseMapping.OrderBy(g => g.Key))
{
    Console.WriteLine(string.Format("{0} => {1}", 
        grouping.Key, string.Join(",", grouping.Select(m => m.Name))));
}

小提琴:https://dotnetfiddle.net/SdE7LD