rom*_*the 7 c# reflection types interface
关于这一点还有其他几个问题,但我觉得它们中没有一个确实提供了可靠的答案.
我最近搞乱反思很多,我想检查实现某个接口的几个程序集中包含的类型.
所以我有一个名为BESCollector的类,它实现了ICollector
public class BESCollector : ICollector
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
在这里,我加载程序集,遍历所有类型,并查看该类型是否包含ICollector类型的接口...
Assembly pluginAssembly = Assembly.ReflectionOnlyLoadFrom(pluginConfig.AssemblyLocation);
IEnumerable<Type> types = pluginAssembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(ICollector)));
Run Code Online (Sandbox Code Playgroud)
......没有结果:(.调试时我可以清楚地看到它包含这种类型.我打破了if循环
Assembly pluginAssembly = Assembly.ReflectionOnlyLoadFrom(pluginConfig.AssemblyLocation);
IEnumerable<Type> types = pluginAssembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(ICollector)));
foreach (Type type in pluginAssembly.GetTypes())
{
Type[] interfaces = type.GetInterfaces();
if (interfaces.Contains(typeof(ICollector)))
{
Console.WriteLine(@"\o/");
}
}
Run Code Online (Sandbox Code Playgroud)
这些结果直接来自调试器.在这里你可以看到它interfaces包含一个Type,即ICollector:
- interfaces {System.Type[1]} System.Type[]
+ [0] {Name = "ICollector" FullName = "SquidReports.DataCollector.Interface.ICollector"} System.Type {System.ReflectionOnlyType}
Run Code Online (Sandbox Code Playgroud)
我要求的类型.GetInterfaces()显然是BESCollector:
+ type {Name = "BESCollector" FullName = "SquidReports.DataCollector.Plugin.BES.BESCollector"} System.Type {System.ReflectionOnlyType}
Run Code Online (Sandbox Code Playgroud)
但是平等陈述interfaces.Contains(typeof(ICollector))永远不会评估为真.
所以你认为我不是在这里混合类型,当我(typeof(ICollector))在调试时鼠标悬停时,它会清楚地显示出来SquidReports.DataCollector.Interface.ICollector.
当然,这确实有效:
Type[] interfaces = type.GetInterfaces();
if (interfaces.Any(t => t.Name == typeof(ICollector).Name))
{
Console.WriteLine(@"\o/");
}
Run Code Online (Sandbox Code Playgroud)
但除了同名的类型之外,这并没有告诉我很多.
而且,为什么这个检查失败了?
if (typeof(ICollector).Equals(typeof(ICollector)))
{
Console.WriteLine("EQUALIZED");
}
Run Code Online (Sandbox Code Playgroud)
为什么我的第一次检查失败?更具体地说,类型相等如何在C#5.0中起作用?对于'Type'类型,.Equals()没有特定的实现吗?
编辑:
如果接口和类在同一个程序集中定义,则在下面的I Quality Catalyst的请求下,如果等式将评估为true,则快速进行测试.这个工作:
class Program
{
public interface ITest
{
}
public class Test : ITest
{
public int ID { get; set; }
}
static void Main(string[] args)
{
Type[] interfaces = (typeof(Test)).GetInterfaces();
if (interfaces.Any(t => t == typeof(ITest)))
{
Console.WriteLine(@"\o/");
}
}
}
Run Code Online (Sandbox Code Playgroud)
EDIT2:这是ICollector的实现
public interface ICollector
{
IDbRelay DbRelay { get; set; }
ILogManager LogManager { get; set; }
void Init(ILogManager logManager, IDbRelay dbRelay);
void Execute();
}
Run Code Online (Sandbox Code Playgroud)
但是,我相信我可能错过了一个重要的细节.我在这里使用三个装配体:
SquidReports.DataCollector我正在进行相等性检查的'Main'()程序集SquidReports.DataCollector.Interface包含ICollector 的'Interface'()程序集SquidReports.DataCollector.Plugin.BES)程序集包含BESCollector的定义注意从InterfaceOnlyAssemblyResolve SquidReports.DataCollector.Interface事件加载'Interface'()可能非常重要,如下所示,因为ReflectionOnlyLoadFrom()不会自动解析依赖关系:
public Assembly ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
// This event is used to resolve dependency problems. We need to return the requested assembly in this method.
// We should probably look in two locations:
// 1. The SquidReports.DataCollector folder
// 2. The Corresponding folder in SquidReports.DataCollector\Plugins
// Let's first turn the 'full' assembly name into something more compact
AssemblyName assemblyName = new AssemblyName(args.Name);
this.Logger.LogMessage(LogLevel.Debug, String.Format("Attempting to resolve Assembly {0} to load {0}", assemblyName.Name, args.RequestingAssembly.GetName().Name));
// Let's also get the location where the requesting assembly is located
DirectoryInfo pluginDirectory = Directory.GetParent(args.RequestingAssembly.Location);
string assemblyFileName = String.Format("{0}.dll", assemblyName.Name);
if (File.Exists(assemblyFileName))
{
// It's in the main bin folder, let's try to load from here
return Assembly.ReflectionOnlyLoadFrom(assemblyFileName);
}
else if (File.Exists(Path.Combine(pluginDirectory.FullName, assemblyFileName)))
{
// It's in the plugin folder, let's load from there
return Assembly.ReflectionOnlyLoadFrom(Path.Combine(pluginDirectory.FullName, assemblyFileName));
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
编辑3:根据Joe的建议,我使用以下方法再次调试应用程序:
if (type.Name == "BESCollector")
{
Type[] interfaces = type.GetInterfaces();
Type interface1 = interfaces[0];
Type interface2 = typeof(ICollector);
Console.WriteLine("");
}
Run Code Online (Sandbox Code Playgroud)
我复制的完整特性interface1和interface2,然后把这些文件中的差异.
我认为结果可能解决了我的问题:
interface1 描述如下:
interface1 {Name = "ICollector" FullName = "SquidReports.DataCollector.Interface.ICollector"} System.Type {System.ReflectionOnlyType}
Run Code Online (Sandbox Code Playgroud)
虽然interface2描述如下:
interface2 {Name = "ICollector" FullName = "SquidReports.DataCollector.Interface.ICollector"} System.Type {System.RuntimeType}
Run Code Online (Sandbox Code Playgroud)
所以我正确地假设问题是由于{System.RuntimeType}!= {System.ReflectionOnlyType}引起的,而Assembly.ReflectionOnlyLoadFrom()应该归咎于此吗?
感谢 Joe Enzminger,我偶然发现了答案:
看来,因为我使用的是 System.ReflectionOnlyType Assembly.ReflectionOnlyLoadFrom(),所以我从 Assembly 加载的 Type 实际上是 System.ReflectionOnlyType,而不是 System.RuntimeType。
基本上,有一个简单且非常酷的解决方案:
ReflectionOnlyLoadFrom()并切换到 LoadFrom()。这可以解决您的所有问题。当然,除非您有充分的理由使用 ReflectionOnlyLoadFrom 。在这种情况下,您可以简单地使用 Type.GUID。无论从哪个上下文加载类型,GUID 都是相同的。所以你可以简单地做
if ((typeof(MyReflectionType)).GUID == (typeof(MyType)).GUID) { // 废话 ... }
这应该可以解决你的问题:)