LINQ to word with multiple keys for single value

时间:2017-08-10 08:34:37

标签: c# linq dictionary

请考虑以下代码:

public KeyAttribute : Attribute{
    public string Value;
    public KeyAttribute(string value){
        Value = value;
    }
}

[Key("A")]
[Key("AB")]
public class A : IClass
{
    public string FieldA {get;set;}
}

[Key("B")]
public class B : IClass
{
    public string FieldB {get;set;}
}

所以我必须完成IClass接口的所有实现,并且我必须构建一个字典Dictionary<string, ConstructorInfo>,其中键是Value KeyAttribute属性,值是相应的ConstructorInfo 请注意,单个类可能有多个KeyAttribute,因此对于这种情况,字典中应该有相应数量的条目。

对于当前示例,期望的结果是:

key     | value
--------+-------------------
"A"     | ConstructorInfo A
"AB"    | ConstructorInfo A
"B"     | ConstructorInfo B

起初我写了这个:

return AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(t => typeof(IClass).IsAssignableFrom(t))
    .ToDictionary(t =>
    {
        var key = (KeyAttribute) t.GetCustomAttributes(typeof(KeyAttribute), true).First();
        return key.Value;
    }, t => t.GetConstructors(BindingFlags.Public).First());

但正如您所看到的,上面的代码不能处理具有多个属性的情况。 所以我做了以下,但这显然是错误的,我不知道如何纠正它。

return AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(t => typeof(IClass).IsAssignableFrom(t))
    .ToDictionary(t =>
    {
        return t.GetCustomAttributes(typeof(KeyAttribute), true).Select(a => ((KeyAttribute)a).Value);
    }, t => t.GetConstructors(BindingFlags.Public).First());

我知道我可以在没有LINQ的情况下做到这一点:

var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(t => typeof(IClass).IsAssignableFrom(t));
var dict = new Dictionary<string, ConstructorInfo>();
foreach (var type in types)
{
    var keys = type.GetCustomAttributes(typeof(KeyAttribute), true).Cast<KeyAttribute>().Select(a => a.Value);
    var ctorInfo = type.GetConstructors(BindingFlags.Public).First();
    foreach (var key in keys)
    {
        dict.Add(key, ctorInfo);
    }
}
return dict;

但如果有可能的话,我宁愿坚持使用LINQ。

对于有关属性的所有这些有些误导性的细节以及所有这些,感到抱歉,虽然它是关于LINQ的问题,但我想不出任何其他生动的例子。

2 个答案:

答案 0 :(得分:3)

这应该有效:

return AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(t => typeof(IClass).IsAssignableFrom(t))
    .SelectMany(t => t.GetCustomAttributes(typeof(KeyAttribute), true)
        .Select(a => new
        {
            constInfo = t.GetConstructors(BindingFlags.Public).First(),
            attrVal = ((KeyAttribute)a).Value 
        }))
    .ToDictionary(entry => entry.attrVal, entry => entry.constInfo);

答案 1 :(得分:1)

SelectMany用于关键属性

return AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(s => s.GetTypes())
                .Where(t => typeof(IClass).IsAssignableFrom(t))
                .SelectMany(t => 
                {
                    return t.GetCustomAttributes<KeyAttribute>()
                            .Select(ka => new
                            {
                                Key = ka,
                                Ctor = t.GetConstructors(BindingFlags.Public).First() 
                            });
                }) 
                .ToDictionary(t => t.Key, t.Ctor);