当通过Type.GetType()
传入的程序集限定名称与实际加载的DLL的版本不同时,是否可以使用Type
获取该类型?如果可以,GetType()
的行为是什么?
我想从一个程序集中获取一个Type
,而不考虑程序集的版本。我有一个函数,该函数将程序集限定名称作为参数:
Type someType = Type.GetType(someName);
someName
值对应于我想要获取的 Type
,但它可能与加载在我的应用程序中的指定 Version
不同。
当通过Type.GetType()
传入的程序集限定名称与实际加载的DLL的版本不同时,是否可以使用Type
获取该类型?如果可以,GetType()
的行为是什么?
我想从一个程序集中获取一个Type
,而不考虑程序集的版本。我有一个函数,该函数将程序集限定名称作为参数:
Type someType = Type.GetType(someName);
someName
值对应于我想要获取的 Type
,但它可能与加载在我的应用程序中的指定 Version
不同。
我已经成功地使用了这个:
Type type = Type.GetType(typeName, AssemblyResolver, null);
private static System.Reflection.Assembly AssemblyResolver(System.Reflection.AssemblyName assemblyName)
{
assemblyName.Version = null;
return System.Reflection.Assembly.Load(assemblyName);
}
在测试中,我发现即使当前加载的程序集版本与程序集限定名称中的Version
字段的值不匹配,GetType()
仍将返回正确的类型。
FullName
和AssemblyName
。在“序列化”时使用:public static string GetShortTypeName(this Type type)
{
return $"{type.FullName}, {type.Assembly.GetName().Name}";
}
或在“反序列化”之前:
public static string ShortenTypeName(string assemblyQualifiedName)
{
var cPos1 = assemblyQualifiedName.IndexOf(',');
if (cPos1 < 0 || cPos1 == assemblyQualifiedName.Length - 1)
return assemblyQualifiedName;
var cPos2 = assemblyQualifiedName.IndexOf(',', cPos1 + 1);
if (cPos2 < 0)
return assemblyQualifiedName;
return assemblyQualifiedName.Substring(0, cPos2);
}
AssemblyResolver
中的assemblyName.Version
始终为null
,因此不再需要自定义解析器。
这适用于 .Net Framework 和 .NET Core/.NET 5+。
GetType()
并给它一个带有错误版本号的类型字符串仍然会返回正确的类型,而不是null。GetType()
方法传递一个不包含版本号的字符串。fullName
将返回一个包含泛型类型参数版本的字符串,你需要自己编写类型字符串。你可以使用我的代码来实现这一点,它使用了@Lars的代码。using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace hlwSerial
{
public static class TypeHelper
{
/// <summary>
/// Gives a shortened assemblyQualifiedName of the type, with only its fullName and the name of its assembly. Does the same for its generic type parameters if it has any.
/// </summary>
/// <param name="type">The type of which you'll get the name</param>
/// <param name="inBrackets">default to false. Put true if the result should be surrounded by brackets in the case of being a generic type parameter.You shouldn't have to set it to true yourself.</param>
/// <returns></returns>
public static string GetShortTypeName(this Type type, bool inBrackets = false)
{
if (type.IsGenericType) return type.GetShortGenericName(inBrackets);
if (inBrackets) return $"[{type.FullName}, {type.Assembly.GetName().Name}]";
return $"{type.FullName}, {type.Assembly.GetName().Name}";
}
/// <summary>
/// Private function that will be called by the GetShortTypeName method if the type tested is generic.
/// </summary>
/// <param name="type">The type of which you'll get the name</param>
/// <param name="inBrackets">default to false. Put true if the result should be surrounded by brackets in the case of being a generic type parameter. You shouldn't have to use this.</param>
/// <returns></returns>
private static string GetShortGenericName(this Type type, bool inBrackets = false)
{
if (inBrackets)
return $"[{type.GetGenericTypeDefinition().FullName}[{string.Join(", ", type.GenericTypeArguments.Select(a => a.GetShortTypeName(true)))}], {type.Assembly.GetName().Name}]";
else
return $"{type.GetGenericTypeDefinition().FullName}[{string.Join(", ",type.GenericTypeArguments.Select(a=> a.GetShortTypeName(true)))}], {type.Assembly.GetName().Name}";
}
}
}