// // Generate the "Signature2" binary serialization string for MethodInfos // // Because the string is effectively a file format for serialized Reflection objects, it must be exactly correct. If missing // metadata prevents generating the string, this method throws a MissingMetadata exception. // public static string SerializationToString(this MethodInfo method) { StringBuilder sb = new StringBuilder(); sb.AppendSerializationString(method.ReturnType); sb.Append(' '); sb.Append(method.Name); if (method.IsGenericMethod) { // Method is a generic method definition or a constructed generic method. Either way, the emit the generic parameters or arguments in brackets. sb.AppendGenericTypeArguments(method.GetGenericArguments()); } sb.Append('('); sb.AppendParameters(method.GetParametersNoCopy(), method.CallingConvention == CallingConventions.VarArgs); sb.Append(')'); return(sb.ToString()); }
// // Generate the "Signature2" binary serialization string for Type objects appearing inside serialized MethodBase and PropertyInfo signatures. // // Because the string is effectively a file format for serialized Reflection objects, it must be exactly correct. If missing // metadata prevents generating the string, this method throws a MissingMetadata exception. // // "withinGenericArgument" is used to track whether we're in the middle of serializing a generic type argument. // Some of the string-generation rules change when in that state: // // - Generic type parameters no longer get prepended with "!" or "!!". // - Plain old types are serialized as assembly-qualified names enclosed in square brackets. // private static void AppendSerializationString(this StringBuilder sb, Type type, bool withinGenericTypeArgument = false) { if (type.HasElementType) { sb.AppendSerializationString(type.GetElementType(), withinGenericTypeArgument); if (type.IsSzArray) { sb.Append("[]"); } else if (type.IsArray) { int rank = type.GetArrayRank(); if (rank == 1) { sb.Append('*'); } else { sb.Append('['); sb.Append(',', rank - 1); sb.Append(']'); } } else if (type.IsByRef) { sb.Append('&'); } else if (type.IsPointer) { sb.Append('*'); } else { Debug.Fail("Should not get here."); throw new InvalidOperationException(); //Unexpected error: Runtime Reflection is a trusted source so we should not have gotten here. } } else if (type.IsGenericParameter) { if (!withinGenericTypeArgument) { // This special rule causes generic type variables ("T") to serialize as "!T" (variable on type) or "!!T" (variable on method) // to distinguish them from a plain old type named "T". // // This rule does not kick in if we're serializing a type variable embedded inside a generic type argument list. (Fortunately, there // is no risk of ambiguity in that case because generic type argument lists always serialize plain old types as "[<assembly-qualified-name>]".) sb.Append('!'); if (type.DeclaringMethod != null) { sb.Append('!'); } } sb.Append(type.Name); } else { // If we got here, "type" is either a plain old type or a constructed generic type. if (withinGenericTypeArgument) { sb.Append('['); } Type plainOldType; Type[] instantiation; SplitIntoPlainOldTypeAndInstantiation(type, out plainOldType, out instantiation); sb.Append(plainOldType.FullName); if (instantiation != null) { sb.AppendGenericTypeArguments(instantiation); } if (withinGenericTypeArgument) { sb.Append(", "); sb.Append(plainOldType.Assembly.FullName); sb.Append(']'); } } }