Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将单个方法映射到多个字符串字典到单个字符串映射到多个方法字典_C#_Linq_Reflection - Fatal编程技术网

C# 将单个方法映射到多个字符串字典到单个字符串映射到多个方法字典

C# 将单个方法映射到多个字符串字典到单个字符串映射到多个方法字典,c#,linq,reflection,C#,Linq,Reflection,我敢说这是我想出的最复杂的题目。 我只是不知道如何更好地解释它,除了这个例子: 我有一个类型。在这种类型下,我有各种各样的方法,其中一些方法附加了一个或多个“OnAttribute”属性,每个属性定义了该方法需要触发的事件名称。我目前正在使用此查询获取一个方法字典,其中包含与事件名称相关的列表: var methods = this.GetType().GetMethods() .Where(m => Attribute.IsDefined(m, typeof(OnAttribut

我敢说这是我想出的最复杂的题目。 我只是不知道如何更好地解释它,除了这个例子:

我有一个类型。在这种类型下,我有各种各样的方法,其中一些方法附加了一个或多个“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
。但是,为了注册方法请求的事件,我需要将每个事件名称映射到请求对其执行的任何和所有方法。换句话说,我需要将前面提到的类型映射到
IEnumerable

我需要这个:

[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
获得方法组,您必须使用
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))));
}

Fiddle:

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

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))));
}

Fiddle:

对于其他希望使用此答案的人:我运行了一些基准测试,使用
新的KeyValuePair(EventName,MethodInfo)
的效率大约是使用
新的{EventName,MethodInfo}
(匿名类型)对于其他希望使用此答案的人的效率的三倍:我运行了一些基准测试,使用
newkeyvaluepair(EventName,MethodInfo)
的效率大约是使用
new{EventName,MethodInfo}
的三倍(匿名类型)