Giải pháp phổ biến này là dành cho những người cần để nạp kiểu generic từ tài liệu tham khảo động bên ngoài bằng cách AssemblyQualifiedName
, mà không biết từ đó lắp ráp được tất cả các phần của kiểu generic đến từ:
public static Type ReconstructType(string assemblyQualifiedName, bool throwOnError = true, params Assembly[] referencedAssemblies)
{
foreach (Assembly asm in referencedAssemblies)
{
var fullNameWithoutAssemblyName = assemblyQualifiedName.Replace($", {asm.FullName}", "");
var type = asm.GetType(fullNameWithoutAssemblyName, throwOnError: false);
if (type != null) return type;
}
if (assemblyQualifiedName.Contains("[["))
{
Type type = ConstructGenericType(assemblyQualifiedName, throwOnError);
if (type != null)
return type;
}
else
{
Type type = Type.GetType(assemblyQualifiedName, false);
if (type != null)
return type;
}
if (throwOnError)
throw new Exception($"The type \"{assemblyQualifiedName}\" cannot be found in referenced assemblies.");
else
return null;
}
private static Type ConstructGenericType(string assemblyQualifiedName, bool throwOnError = true)
{
Regex regex = new Regex(@"^(?<name>\w+(\.\w+)*)`(?<count>\d)\[(?<subtypes>\[.*\])\](, (?<assembly>\w+(\.\w+)*)[\w\s,=\.]+)$?", RegexOptions.Singleline | RegexOptions.ExplicitCapture);
Match match = regex.Match(assemblyQualifiedName);
if (!match.Success)
if (!throwOnError) return null;
else throw new Exception($"Unable to parse the type's assembly qualified name: {assemblyQualifiedName}");
string typeName = match.Groups["name"].Value;
int n = int.Parse(match.Groups["count"].Value);
string asmName = match.Groups["assembly"].Value;
string subtypes = match.Groups["subtypes"].Value;
typeName = typeName + $"`{n}";
Type genericType = ReconstructType(typeName, throwOnError);
if (genericType == null) return null;
List<string> typeNames = new List<string>();
int ofs = 0;
while (ofs < subtypes.Length && subtypes[ofs] == '[')
{
int end = ofs, level = 0;
do
{
switch (subtypes[end++])
{
case '[': level++; break;
case ']': level--; break;
}
} while (level > 0 && end < subtypes.Length);
if (level == 0)
{
typeNames.Add(subtypes.Substring(ofs + 1, end - ofs - 2));
if (end < subtypes.Length && subtypes[end] == ',')
end++;
}
ofs = end;
n--;
}
if (n != 0)
throw new Exception("Generic type argument count mismatch! Type name: " + assemblyQualifiedName);
Type[] types = new Type[typeNames.Count];
for (int i = 0; i < types.Length; i++)
{
try
{
types[i] = ReconstructType(typeNames[i], throwOnError);
if (types[i] == null)
return null;
}
catch (Exception ex)
{
throw new Exception($"Unable to reconstruct generic type. Failed on creating the type argument {(i + 1)}: {typeNames[i]}. Error message: {ex.Message}");
}
}
Type resultType = genericType.MakeGenericType(types);
return resultType;
}
Và bạn có thể kiểm tra nó bằng mã này (ứng dụng bảng điều khiển):
static void Main(string[] args)
{
Type t1 = typeof(Task<Dictionary<int, Dictionary<string, int?>>>);
string name = t1.AssemblyQualifiedName;
Console.WriteLine("Type: " + name);
Type t2 = ReconstructType(name);
bool ok = t1 == t2;
Console.WriteLine("\r\nLocal type test OK: " + ok);
Assembly asmRef = Assembly.ReflectionOnlyLoad("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
string refTypeTest = "System.Threading.Tasks.Task`1[[System.Windows.Forms.DialogResult, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
Type t3 = ReconstructType(refTypeTest, true, asmRef);
Console.WriteLine("External type test OK: " + (t3.AssemblyQualifiedName == refTypeTest));
Type t4 = ReconstructType("System.Windows.Forms.DialogResult, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", true, asmRef);
Console.ReadLine();
}
Tôi đang chia sẻ giải pháp của mình để giúp những người có cùng vấn đề như tôi (giải mã hóa BẤT KỲ loại nào từ chuỗi có thể được xác định cả một phần hoặc toàn bộ trong assembly được tham chiếu bên ngoài - và các tham chiếu được thêm động bởi người dùng ứng dụng).
Hy vọng nó sẽ giúp bất cứ ai!