gpt4 book ai didi

c# - 如何从动态加载的程序集中加载包含嵌套类型的泛型类型?

转载 作者:行者123 更新时间:2023-11-30 15:12:48 24 4
gpt4 key购买 nike

在使用 Assembly.LoadFrom 加载到当前 AppDomain 的程序集中,我有以下代码:

[TypeConverter(typeof(EnumConverter<Shapes>))]
public enum Shapes
{
Triangle,
Square,
Circle
}

通用 EnumConverter 在调用 Assembly.GetEntryAssembly() 返回的程序集中定义。当我在运行时读取 TypeConverter 属性时,我得到了类似于以下内容的类型的全名:

MyAssembly.EnumConverter`1[[MyDynamicAssembly.Shapes, MyDynamicAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

但是,当我对字符串调用 Type.GetType() 时,它返回 null。我希望能够获得 System.Type 的实例。另请注意,MyDynamicAssembly 不是由 Reflection.Emit 生成的(在 MSDN 文章 here 中指出)。

此代码是在 Visual Studio 2005 上使用 .NET Framework 2.0 生成的。

有没有人找到解决此错误/限制的方法?它在 3.5 中修复了吗?

最佳答案

跟随 MSDN forum posting 的线索后,我能够整合一个通用解决方案,用于从运行时加载的程序集中加载任意泛型类型。我希望这对某些人有所帮助(也许 Microsoft 会在 .NET 4.0 中加入一些等效的东西?)

public static class TypeHelpers
{
/// <summary>
/// Gets the System.Type with the specified name, performing a case-sensitive search.
/// </summary>
/// <param name="typeName">The assembly-qualified name of the type to get. See System.Type.AssemblyQualifiedName.</param>
/// <param name="throwOnError">Whether or not to throw an exception or return null if the type was not found.</param>
/// <param name="ignoreCase">Whether or not to perform a case-insensitive search.</param>
/// <returns>The System.Type with the specified name.</returns>
/// <remarks>
/// This method can load types from dynamically loaded assemblies as long as the referenced assembly
/// has already been loaded into the current AppDomain.
/// </remarks>
public static Type GetType(string typeName, bool throwOnError, bool ignoreCase)
{
if(string.IsNullOrEmpty(typeName))
throw new ArgumentNullException("typeName");

// handle the trivial case
Type type;
if((type = Type.GetType(typeName, false, ignoreCase)) != null)
return type;

// otherwise, perform the recursive search
try
{
return GetTypeFromRecursive(typeName, ignoreCase);
}
catch(Exception e)
{
if(throwOnError)
throw;
}

return null;
}

#region Private Static Helper Methods

private static Type GetTypeFromRecursive(string typeName, bool ignoreCase)
{
int startIndex = typeName.IndexOf('[');
int endIndex = typeName.LastIndexOf(']');

if(startIndex == -1)
{
// try to load the non-generic type (e.g. System.Int32)
return TypeHelpers.GetNonGenericType(typeName, ignoreCase);
}
else
{
// determine the cardinality of the generic type
int cardinalityIndex = typeName.IndexOf('`', 0, startIndex);
string cardinalityString = typeName.Substring(cardinalityIndex + 1, startIndex - cardinalityIndex - 1);
int cardinality = int.Parse(cardinalityString);

// get the FullName of the non-generic type (e.g. System.Collections.Generic.List`1)
string fullName = typeName.Substring(0, startIndex);
if(typeName.Length - endIndex - 1 > 0)
fullName += typeName.Substring(endIndex + 1, typeName.Length - endIndex - 1);

// parse the child type arguments for this generic type (recursive)
List<Type> list = new List<Type>();
string typeArguments = typeName.Substring(startIndex + 1, endIndex - startIndex - 1);
foreach(string item in EachAssemblyQualifiedName(typeArguments, cardinality))
{
Type typeArgument = GetTypeFromRecursive(item, ignoreCase);
list.Add(typeArgument);
}

// construct the generic type definition
return TypeHelpers.GetNonGenericType(fullName, ignoreCase).MakeGenericType(list.ToArray());
}
}

private static IEnumerable<string> EachAssemblyQualifiedName(string s, int count)
{
Debug.Assert(count != 0);
Debug.Assert(string.IsNullOrEmpty(s) == false);
Debug.Assert(s.Length > 2);

// e.g. "[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]"
// e.g. "[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.DateTime, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]"
// e.g. "[System.Collections.Generic.KeyValuePair`2[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.DateTime, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]"

int startIndex = 0;
int bracketCount = 0;

while(count > 0)
{
bracketCount = 0;

for(int i = startIndex; i < s.Length; i++)
{
switch(s[i])
{
case '[':
bracketCount++;
continue;

case ']':
if(--bracketCount == 0)
{
string item = s.Substring(startIndex + 1, i - startIndex - 1);
yield return item;
startIndex = i + 2;
}
break;

default:
continue;
}
}

if(bracketCount != 0)
{
const string SR_Malformed = "The brackets are unbalanced in the string, '{0}'.";
throw new FormatException(string.Format(SR_Malformed, s));
}

count--;
}
}

private static Type GetNonGenericType(string typeName, bool ignoreCase)
{
// assume the type information is not a dynamically loaded assembly
Type type = Type.GetType(typeName, false, ignoreCase);
if(type != null)
return type;

// otherwise, search the assemblies in the current AppDomain for the type
int assemblyFullNameIndex = typeName.IndexOf(',');
if(assemblyFullNameIndex != -1)
{
string assemblyFullName = typeName.Substring(assemblyFullNameIndex + 2, typeName.Length - assemblyFullNameIndex - 2);
foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if(assembly.GetName().FullName == assemblyFullName)
{
string fullName = typeName.Substring(0, assemblyFullNameIndex);
type = assembly.GetType(fullName, false, ignoreCase);
if(type != null)
return type;
}
}
}

// no luck? blow up
const string SR_TypeNotFound = "The type, '{0}', was not found.";
throw new ArgumentException(string.Format(SR_TypeNotFound, typeName), "typeName");
}

#endregion
}

此代码已通过上述场景和以下 MbUnit 测试进行了测试:

[Test]
public void GetType_DictionaryOfStringAndDictionaryOfInt32AndKeyValuePairOfStringAndListOfInt32()
{
Dictionary<string, Dictionary<int, KeyValuePair<string, List<int>>>> obj =
new Dictionary<string, Dictionary<int, KeyValuePair<string, List<int>>>>();

string typeName = obj.GetType().FullName;
Type type = TypeHelpers.GetType(typeName, true, false);

Assert.IsTrue(type.Equals(obj.GetType()));
}

注意:尝试使用此测试时应注释掉琐碎的处理程序,否则将调用 Type.GetType() 而不是实际的解析代码。

关于c# - 如何从动态加载的程序集中加载包含嵌套类型的泛型类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/660607/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com