Type序列化器
阿新 • • 發佈:2020-09-16
用於將Type和Type名稱相互轉化
public class TypeNameSerializer { private readonly ConcurrentDictionary<Type, string> serializedTypes = new ConcurrentDictionary<Type, string>(); private readonly ConcurrentDictionary<string, Type> deSerializedTypes = new ConcurrentDictionary<string, Type>(); /// <inheritdoc /> public string Serialize(Type type) { return serializedTypes.GetOrAdd(type, t => { var typeName = RemoveAssemblyDetails(t.AssemblyQualifiedName); return typeName; }); } /// <inheritdoc /> public Type DeSerialize(string typeName) { return deSerializedTypes.GetOrAdd(typeName, t => { var typeNameKey = SplitFullyQualifiedTypeName(t); return GetTypeFromTypeNameKey(typeNameKey); }); } private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) { var builder = new StringBuilder(fullyQualifiedTypeName.Length); // loop through the type name and filter out qualified assembly details from nested type names var writingAssemblyName = false; var skippingAssemblyDetails = false; foreach (var character in fullyQualifiedTypeName) { switch (character) { case '[': writingAssemblyName = false; skippingAssemblyDetails = false; builder.Append(character); break; case ']': writingAssemblyName = false; skippingAssemblyDetails = false; builder.Append(character); break; case ',': if (!writingAssemblyName) { writingAssemblyName = true; builder.Append(character); } else { skippingAssemblyDetails = true; } break; default: if (!skippingAssemblyDetails) { builder.Append(character); } break; } } return builder.ToString(); } private static TypeNameKey SplitFullyQualifiedTypeName(string fullyQualifiedTypeName) { var assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName); string typeName; string assemblyName; if (assemblyDelimiterIndex != null) { typeName = Trim(fullyQualifiedTypeName,0, assemblyDelimiterIndex.GetValueOrDefault()); assemblyName = Trim(fullyQualifiedTypeName,assemblyDelimiterIndex.GetValueOrDefault() + 1, fullyQualifiedTypeName.Length - assemblyDelimiterIndex.GetValueOrDefault() - 1); } else { typeName = fullyQualifiedTypeName; assemblyName = null; } return new TypeNameKey(assemblyName, typeName); } private static Type GetTypeFromTypeNameKey(TypeNameKey typeNameKey) { var assemblyName = typeNameKey.AssemblyName; var typeName = typeNameKey.TypeName; if (assemblyName != null) { var assembly = Assembly.Load(new AssemblyName(assemblyName)); if (assembly == null) { var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var a in loadedAssemblies) { if (a.FullName == assemblyName || a.GetName().Name == assemblyName) { assembly = a; break; } } } if (assembly == null) { throw new Exception($"Could not load assembly '{assemblyName}'"); } var type = assembly.GetType(typeName); if (type == null) { // if generic type, try manually parsing the type arguments for the case of dynamically loaded assemblies // example generic typeName format: System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] if (typeName.IndexOf('`') >= 0) { try { type = GetGenericTypeFromTypeName(typeName, assembly); } catch (Exception ex) { throw new Exception($"Could not find type '{typeName}' in assembly '{assembly.FullName}'", ex); } } if (type == null) { throw new Exception($"Could not find type '{typeName}' in assembly '{assembly.FullName}'"); } } return type; } return Type.GetType(typeName); } private static Type GetGenericTypeFromTypeName(string typeName, Assembly assembly) { Type type = null; var openBracketIndex = typeName.IndexOf('['); if (openBracketIndex >= 0) { var genericTypeDefName = typeName.Substring(0, openBracketIndex); var genericTypeDef = assembly.GetType(genericTypeDefName); if (genericTypeDef != null) { var genericTypeArguments = new List<Type>(); var scope = 0; var typeArgStartIndex = 0; var endIndex = typeName.Length - 1; for (var i = openBracketIndex + 1; i < endIndex; ++i) { var current = typeName[i]; switch (current) { case '[': if (scope == 0) { typeArgStartIndex = i + 1; } ++scope; break; case ']': --scope; if (scope == 0) { var typeArgAssemblyQualifiedName = typeName.Substring(typeArgStartIndex, i - typeArgStartIndex); var typeNameKey = SplitFullyQualifiedTypeName(typeArgAssemblyQualifiedName); genericTypeArguments.Add(GetTypeFromTypeNameKey(typeNameKey)); } break; } } type = genericTypeDef.MakeGenericType(genericTypeArguments.ToArray()); } } return type; } private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName) { // we need to get the first comma following all surrounded in brackets because of generic types // e.g. System.Collections.Generic.Dictionary`2[[System.String, mscorlib,Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 var scope = 0; for (var i = 0; i < fullyQualifiedTypeName.Length; i++) { var current = fullyQualifiedTypeName[i]; switch (current) { case '[': scope++; break; case ']': scope--; break; case ',': if (scope == 0) { return i; } break; } } return null; } public static string Trim(string s, int start, int length) { // References: https://referencesource.microsoft.com/#mscorlib/system/string.cs,2691 // https://referencesource.microsoft.com/#mscorlib/system/string.cs,1226 if (s == null) { throw new ArgumentNullException(nameof(s)); } if (start < 0) { throw new ArgumentOutOfRangeException(nameof(start)); } if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var end = start + length - 1; if (end >= s.Length) { throw new ArgumentOutOfRangeException(nameof(length)); } for (; start < end; start++) { if (!char.IsWhiteSpace(s[start])) { break; } } for (; end >= start; end--) { if (!char.IsWhiteSpace(s[end])) { break; } } return s.Substring(start, end - start + 1); } private struct TypeNameKey { public string AssemblyName { get; } public string TypeName { get; } public TypeNameKey(string assemblyName, string typeName) { AssemblyName = assemblyName; TypeName = typeName; } } }
客戶端:
public static void Main(string[] args) { TypeNameSerializer serializer = new TypeNameSerializer(); //將Type序列化為Name string typeName = serializer.Serialize(typeof(Program)); //將Name反序列化為Type Type type = serializer.DeSerialize(typeName); //泛型 typeName = serializer.Serialize(typeof(People<>)); type = serializer.DeSerialize(typeName); Console.ReadKey(); return; }