我正在尝试使用StructureMap来执行运行时类型注册,而我在使用Type.GetType()
在引用的程序集中查找类型时遇到了问题。以下是我的测试应用的完整代码:
using System;
using System.Collections.Generic;
using System.Linq;
using StructureMap;
using StructureMap.Configuration.DSL;
using StructureMap.Graph;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
ObjectFactory.Initialize(r => r.Scan(
s => {
s.AssembliesFromPath(
@"c:\Path\To\MyClasses\bin\Debug");
s.Convention<MyConvention>();
}
));
ObjectFactory.AssertConfigurationIsValid();
foreach (var name in MyConvention.assemblyQualifiedTypenames) {
Console.WriteLine(name);
Console.WriteLine("Type found for reflection by assembly qualified name: {0}", Type.ReflectionOnlyGetType(name, false, false) != null);
Console.WriteLine("Type found by assembly qualified name: {0}", Type.GetType(name) != null);
Console.WriteLine("Type found by search: {0}",
AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany(assembly => assembly.GetTypes().Where(t => t.AssemblyQualifiedName == name))
.FirstOrDefault() != null
);
}
Type type = null;
foreach (var name in MyConvention.fullnames) {
Console.WriteLine(name);
Console.WriteLine("Type found by full name: {0}", Type.GetType(name) != null);
Console.WriteLine("Type found by search: {0}",
AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany(assembly => assembly.GetTypes().Where(t => t.FullName == name))
.FirstOrDefault() != null
);
}
foreach (var name in MyConvention.typenames) {
Console.WriteLine(name);
Console.WriteLine("Type found by name: {0}", Type.GetType(name) != null);
Console.WriteLine("Type found by search: {0}",
(type = AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany(assembly => assembly.GetTypes().Where(t => t.Name == name))
.FirstOrDefault()) != null
);
}
Console.ReadLine();
var instance = ObjectFactory.GetInstance(type);
Console.WriteLine("Type instance retrieved from StructureMap: {0}", instance != null);
Console.ReadLine();
ObjectFactory.WhatDoIHave()
.Split(new [] { Environment.NewLine}, StringSplitOptions.None)
.Where(s => s.Contains("Class2")).ToList()
.ForEach(Console.WriteLine);
Console.ReadLine();
}
private class MyConvention : IRegistrationConvention {
public static List<string> typenames = new List<string>();
public static List<string> fullnames = new List<string>();
public static List<string> assemblyQualifiedTypenames = new List<string>();
public void Process(Type type, Registry registry) {
if (type.GetCustomAttributes(false).Any(o => o.GetType().Name == "MyClassAttribute")) {
registry.For(type).Use(type);
typenames.Add(type.Name);
fullnames.Add(type.FullName);
assemblyQualifiedTypenames.Add(type.AssemblyQualifiedName);
}
}
}
}
}
测试类定义:
namespace MyAttributes {
public class MyClassAttribute : Attribute { }
}
namespace MyClasses {
public class MyClass1 { }
[MyClass]
public class MyClass2 { }
}
运行控制台应用程序的输出:
MyClasses.Class2, MyClasses, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Type found for reflection by assembly qualified name: False Type found by assembly qualified name: False Type found by search: True MyClasses.Class2 Type found by full name: False Type found by search: True Class2 Type found by name: False Type found by search: True Type instance retrieved from StructureMap: True Class2 (MyClasses.Class2) 60eb30ad-ae50-413d-884f-04743ea3148c Configured Instance of MyClasses.Class2, MyClasses, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 60eb30ad-ae50-413d-884f-04743ea3148c Configured Instance of MyClasses.Class2, MyClasses, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
我已经完成了基于this SO post的所有测试 - 我是否遗漏了一些基本的东西?
答案 0 :(得分:1)
问题是您尝试使用Type.GetType(name)
获取类型。因此.net将尝试找到程序集本身 - 在GAC或与执行程序集相同的目录中。由于它位于不同的目录中,因此无法找到它。您可以通过将包含MyClasses
的可执行文件复制到与控制台应用程序相同的目录中来确认这一点 - 然后它可以正常工作。
由于类似的原因,它不在AppDomain.CurrentDomain.GetAssemblies()
,因为当前域中没有任何内容使用MyClasses
。
您需要加载从MyConvention.assemblyQualifiedTypenames
返回的程序集,然后使用assembly.GetType(name)
,或使用Type.GetType
版本,它允许您指定自己的程序集解析程序,如{{3} (仅当类包含程序集名称时才有效。)
答案 1 :(得分:1)
试试这段代码。这避免了使用程序集限定名称,因此没有版本控制的硬编码。
const string myClass = "<Namespace.Class>";
const string dllName = "<DllName>,"; //Notice the ','
Type myType = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.ToString().StartsWith(dllName)).Select(a => a.GetType(myClass )).FirstOrDefault();