我认为我有精神障碍,但有人可以请教我如何将这两个LINQ语句合并为一个吗?
/// <summary>
/// Returns an array of Types that implement the supplied generic interface in the
/// current AppDomain.
/// </summary>
/// <param name="interfaceType">Type of generic interface implemented</param>
/// <param name="includeAbstractTypes">Include Abstract class types in the search</param>
/// <param name="includeInterfaceTypes">Include Interface class types in the search</param>
/// <returns>Array of Types that implement the supplied generic interface</returns>
/// <remarks>
/// History.<br/>
/// 10/12/2008 davide Method creation.<br/>
/// </remarks>
public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool includeAbstractTypes, bool includeInterfaceTypes)
{
// Use linq to find types that implement the supplied interface.
var allTypes = AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany(s => s.GetTypes())
.Where(p => p.IsAbstract == includeAbstractTypes
&& p.IsInterface == includeInterfaceTypes);
var implementingTypes = from type in allTypes
from intf in type.GetInterfaces().ToList()
where intf.FullName != null && intf.FullName.Contains(interfaceType.FullName)
select type;
return implementingTypes.ToArray<Type>();
}
我正在避免IsAssignableFrom,因为它似乎在不提供特定类型的通用接口时失败,因此我认为在IsAssignableFrom上使用FullName caparison应该足够了,例如:
namespace Davide
{
interface IOutput<TOutputType> { }
class StringOutput : IOutput<string> { }
}
typeof(IOutput&lt;&gt;)。FullName将返回“Davide + IOutput`1”
typeof(StringOutput).GetInterfaces()[0] .FullName将返回“Davide + IOutput`1 [[System.String,mscorlib,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]”
因此使用FullName.Contains就足够了
答案 0 :(得分:3)
SelectMany转换为第二个“from”:
var implementors = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where type.IsAbstract == includeAbstractTypes
where type.IsInterface == includeInterfaceTypes
from intf in type.GetInterfaces()
where intf.FullName != null &&
intf.FullName.Contains(interfaceType.FullName)
select type;
我已将条件分为多个“where”条款,主观清晰,顺便说一句。
这编译,但我还没有测试它是否真的有效:)正如另一个答案所示,你可以使用GetInterfaces()而不是最终的“from”子句来使用“Any”。
请注意,不需要一直调用ToList() - LINQ旨在能够处理整个序列。
顺便说一下,我不确定你为什么要通过type.GetInterfaces()来检查。与使用Type.IsAssignableFrom相比,是否有任何不同(和可取的)?那样会更简单:
var implementors = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where type.IsAbstract == includeAbstractTypes
where type.IsInterface == includeInterfaceTypes
where interfaceType.IsAssignableFrom(type)
select type;
在某个地方,您实际上在不同的程序集中具有相同的接口类型名称吗?
答案 1 :(得分:1)
会这样做:
public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool includeAbstractTypes, bool includeInterfaceTypes)
{
// Use linq to find types that implement the supplied interface.
var allTypes = AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany(s => s.GetTypes())
.Where(p => p.IsAbstract == includeAbstractTypes
&& p.IsInterface == includeInterfaceTypes
&& p.GetInterfaces().Any(i=>i.FullName != null && i.FullName.Contains(interfaceType.FullName))
);
//var implementingTypes = from type in allTypes
// from intf in type.GetInterfaces().ToList()
// where intf.FullName != null && intf.FullName.Contains(interfaceType.FullName)
// select type;
//return implementingTypes.ToArray<Type>();
return allTypes.ToArray();
}
答案 2 :(得分:1)
我可以提出另一种解决方案吗?
public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool includeAbstractTypes, bool includeInterfaceTypes)
{
// Use linq to find types that implement the supplied interface.
var implementingTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => interfaceType.IsAssignableFrom(p)
&& (
(p.IsAbstract && includeAbstractTypes)
|| (p.IsInterface && includeInterfaceTypes)
|| (!p.IsAbstract && !p.IsInterface)
)
);
return implementingTypes.ToArray<Type>();
}
答案 3 :(得分:0)
经过与Jon Skeet的简短讨论并稍作思考后,我发布了以下答案。我改变了方法以使用GetGenericTypeDefinition而不是FullName.Contains,这将是一个更强大的解决方案。我还更改了LINQ查询IsAbstract和IsInterface的Where子句,因为它们没有按预期排除类型。感谢大家的反馈。
/// <summary>
/// Returns an array of Types that implement the supplied generic interface in the
/// current AppDomain.
/// </summary>
/// <param name="interfaceType">Type of generic interface implemented</param>
/// <param name="excludeAbstractTypes">Exclude Abstract class types in the search</param>
/// <param name="excludeInterfaceTypes">Exclude Interface class types in the search</param>
/// <returns>Array of Types that implement the supplied generic interface</returns>
/// <remarks>
/// History.<br/>
/// 11/12/2008 davide Created method.<br/>
/// 11/12/2008 davide Altered method to use a two LINQ query pass.<br/>
/// 11/12/2008 davide Altered method to use optimised combined LINQ query.<br/>
/// 12/12/2008 davide Altered method and replaced FullName criteria match with GetGenericTypeDefinition.<br/>
/// </remarks>
public static Type[] GetTypesImplementingGenericInterface(Type interfaceType, bool excludeAbstractTypes, bool excludeInterfaceTypes)
{
if (!interfaceType.IsGenericType)
{
throw new ArgumentException("Supplied interface is not a Generic type");
}
if (interfaceType.ContainsGenericParameters)
{
interfaceType = interfaceType.GetGenericTypeDefinition();
}
// Use linq to find types that implement the supplied generic interface.
var implementingTypes = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where (type.IsAbstract != excludeAbstractTypes) || (!excludeAbstractTypes)
where (type.IsInterface != excludeInterfaceTypes) || (!excludeInterfaceTypes)
from intf in type.GetInterfaces()
where intf.IsGenericType && intf.GetGenericTypeDefinition() == interfaceType
select type;
return implementingTypes.ToArray<Type>();
}