我敢说这是我想出的最复杂的标题。 我只是不确定如何更好地解释它,除了这个例子:
我有一个类型。 在这种类型下,我有各种各样的方法,其中一些方法附加了一个或多个"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() 与一些匿名类型一起使用,将字典平展为一个列表,然后使用 GroupBy 将该列表重新分组到我想要的字典中,但这似乎效率低下且混乱。 我想知道执行此操作的(最佳)LINQ 方法。
我希望这至少有点道理。
感谢您的任何帮助!
您必须结合使用SelectMany
和GroupBy
才能获得所需的结果。
这是一个似乎有效的解决方案:
var 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
和MethodInfo
的匿名类型的中间集合。这个匿名类型的中间集合如果然后按EventName
分组以获取按EventName
的方法组。
要从当前的方法字典中获取反向映射,您可以执行以下操作:
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