using System; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Text; using System.Text.RegularExpressions; using ILRuntime.Runtime.Enviorment; using ILRuntime.Other; namespace ILRuntime.Runtime.CLRBinding { public class BindingCodeGenerator { public static void GenerateBindingCode(List types, string outputPath, HashSet excludeMethods = null, HashSet excludeFields = null, List valueTypeBinders = null, List delegateTypes = null) { if (!System.IO.Directory.Exists(outputPath)) System.IO.Directory.CreateDirectory(outputPath); string[] oldFiles = System.IO.Directory.GetFiles(outputPath, "*.cs"); foreach (var i in oldFiles) { System.IO.File.Delete(i); } List clsNames = new List(); foreach (var i in types) { string clsName, realClsName; bool isByRef; if (i.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > 0) continue; i.GetClassName(out clsName, out realClsName, out isByRef); clsNames.Add(clsName); using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/" + clsName + ".cs", false, new UTF8Encoding(false))) { StringBuilder sb = new StringBuilder(); sb.Append(@"using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using ILRuntime.CLR.TypeSystem; using ILRuntime.CLR.Method; using ILRuntime.Runtime.Enviorment; using ILRuntime.Runtime.Intepreter; using ILRuntime.Runtime.Stack; using ILRuntime.Reflection; using ILRuntime.CLR.Utils; namespace ILRuntime.Runtime.Generated { unsafe class "); sb.AppendLine(clsName); sb.Append(@" { public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app) { "); string flagDef = " BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;"; string methodDef = " MethodBase method;"; string methodsDef = " MethodInfo[] methods = type.GetMethods(flag).Where(t => !t.IsGenericMethod).ToArray();"; string fieldDef = " FieldInfo field;"; string argsDef = " Type[] args;"; string typeDef = string.Format(" Type type = typeof({0});", realClsName); bool needMethods; MethodInfo[] methods = i.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); FieldInfo[] fields = i.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); string registerMethodCode = i.GenerateMethodRegisterCode(methods, excludeMethods, out needMethods); string registerFieldCode = i.GenerateFieldRegisterCode(fields, excludeFields); string registerValueTypeCode = i.GenerateValueTypeRegisterCode(realClsName); string registerMiscCode = i.GenerateMiscRegisterCode(realClsName, true, true); string commonCode = i.GenerateCommonCode(realClsName); ConstructorInfo[] ctors = i.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); string ctorRegisterCode = i.GenerateConstructorRegisterCode(ctors, excludeMethods); string methodWraperCode = i.GenerateMethodWraperCode(methods, realClsName, excludeMethods, valueTypeBinders, null); string fieldWraperCode = i.GenerateFieldWraperCode(fields, realClsName, excludeFields, valueTypeBinders, null); string cloneWraperCode = i.GenerateCloneWraperCode(fields, realClsName); string ctorWraperCode = i.GenerateConstructorWraperCode(ctors, realClsName, excludeMethods, valueTypeBinders); bool hasMethodCode = !string.IsNullOrEmpty(registerMethodCode); bool hasFieldCode = !string.IsNullOrEmpty(registerFieldCode); bool hasValueTypeCode = !string.IsNullOrEmpty(registerValueTypeCode); bool hasMiscCode = !string.IsNullOrEmpty(registerMiscCode); bool hasCtorCode = !string.IsNullOrEmpty(ctorRegisterCode); bool hasNormalMethod = methods.Where(x => !x.IsGenericMethod).Count() != 0; if ((hasMethodCode && hasNormalMethod) || hasFieldCode || hasCtorCode) sb.AppendLine(flagDef); if (hasMethodCode || hasCtorCode) sb.AppendLine(methodDef); if (hasFieldCode) sb.AppendLine(fieldDef); if (hasMethodCode || hasFieldCode || hasCtorCode) sb.AppendLine(argsDef); if (hasMethodCode || hasFieldCode || hasValueTypeCode || hasMiscCode || hasCtorCode) sb.AppendLine(typeDef); if (needMethods) sb.AppendLine(methodsDef); sb.AppendLine(registerMethodCode); sb.AppendLine(registerFieldCode); sb.AppendLine(registerValueTypeCode); sb.AppendLine(registerMiscCode); sb.AppendLine(ctorRegisterCode); sb.AppendLine(" }"); sb.AppendLine(); sb.AppendLine(commonCode); sb.AppendLine(methodWraperCode); sb.AppendLine(fieldWraperCode); sb.AppendLine(cloneWraperCode); sb.AppendLine(ctorWraperCode); sb.AppendLine(" }"); sb.AppendLine("}"); sw.Write(Regex.Replace(sb.ToString(), "(? Methods { get; set; } public HashSet Fields { get; set; } public HashSet Constructors { get; set; } public bool ArrayNeeded { get; set; } public bool DefaultInstanceNeeded { get; set; } public bool ValueTypeNeeded { get; set; } public bool NeedGenerate { get { if (Methods.Count == 0 && Constructors.Count == 0 && Fields.Count == 0 && !ArrayNeeded && !DefaultInstanceNeeded && !ValueTypeNeeded) return false; else { //Making CLRBinding for such types makes no sense if (Type == typeof(Delegate) || Type == typeof(System.Runtime.CompilerServices.RuntimeHelpers)) return false; return true; } } } } internal class FileNameEqualityComparer : IEqualityComparer { public bool Equals(string x, string y) { // handle null cases first if (x == null) return (y == null); // x != null else if (y == null) return false; return x.Equals(y, StringComparison.OrdinalIgnoreCase); } public int GetHashCode(string obj) { int hashCode = 0; if (obj != null) { hashCode = obj.GetHashCode(); } return hashCode; } } public static void GenerateBindingCode(ILRuntime.Runtime.Enviorment.AppDomain domain, string outputPath, List valueTypeBinders = null, List delegateTypes = null, params string[] excludeFiles) { if (domain == null) return; if (!System.IO.Directory.Exists(outputPath)) System.IO.Directory.CreateDirectory(outputPath); Dictionary infos = new Dictionary(new ByReferenceKeyComparer()); CrawlAppdomain(domain, infos); string[] oldFiles = System.IO.Directory.GetFiles(outputPath, "*.cs"); foreach (var i in oldFiles) { System.IO.File.Delete(i); } if (valueTypeBinders == null) valueTypeBinders = new List(domain.ValueTypeBinders.Keys); HashSet excludeMethods = null; HashSet excludeFields = null; HashSet files = new HashSet(); List clsNames = new List(); FileNameEqualityComparer fileNameEqualityComparer = new FileNameEqualityComparer(); foreach (var info in infos) { if (!info.Value.NeedGenerate) continue; Type i = info.Value.Type; //CLR binding for delegate is important for cross domain invocation,so it should be generated //if (i.BaseType == typeof(MulticastDelegate)) // continue; string clsName, realClsName; bool isByRef; if (i.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > 0) continue; i.GetClassName(out clsName, out realClsName, out isByRef); if (excludeFiles.Contains(clsName)) continue; int extraClsNameIndex = 0; string oClsName = clsName; while (clsNames.Contains(oClsName)) { extraClsNameIndex++; oClsName = clsName + "_t" + extraClsNameIndex; } clsNames.Add(oClsName); clsName = oClsName; //File path length limit string oriFileName = outputPath + "/" + clsName; int len = Math.Min(oriFileName.Length, 100); if (len < oriFileName.Length) oriFileName = oriFileName.Substring(0, len); int extraNameIndex = 0; string oFileName = oriFileName; while (files.Contains(oFileName, fileNameEqualityComparer)) { extraNameIndex++; oFileName = oriFileName + "_t" + extraNameIndex; } files.Add(oFileName); oFileName = oFileName + ".cs"; using (System.IO.StreamWriter sw = new System.IO.StreamWriter(oFileName, false, new UTF8Encoding(false))) { StringBuilder sb = new StringBuilder(); sb.Append(@"using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using ILRuntime.CLR.TypeSystem; using ILRuntime.CLR.Method; using ILRuntime.Runtime.Enviorment; using ILRuntime.Runtime.Intepreter; using ILRuntime.Runtime.Stack; using ILRuntime.Reflection; using ILRuntime.CLR.Utils; namespace ILRuntime.Runtime.Generated { unsafe class "); sb.AppendLine(clsName); sb.Append(@" { public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app) { "); string flagDef = " BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;"; string methodDef = " MethodBase method;"; string methodsDef = " MethodInfo[] methods = type.GetMethods(flag).Where(t => !t.IsGenericMethod).ToArray();"; string fieldDef = " FieldInfo field;"; string argsDef = " Type[] args;"; string typeDef = string.Format(" Type type = typeof({0});", realClsName); bool needMethods; MethodInfo[] methods = info.Value.Methods.ToArray(); FieldInfo[] fields = info.Value.Fields.ToArray(); string registerMethodCode = i.GenerateMethodRegisterCode(methods, excludeMethods, out needMethods); string registerFieldCode = fields.Length > 0 ? i.GenerateFieldRegisterCode(fields, excludeFields) : null; string registerValueTypeCode = info.Value.ValueTypeNeeded ? i.GenerateValueTypeRegisterCode(realClsName) : null; string registerMiscCode = i.GenerateMiscRegisterCode(realClsName, info.Value.DefaultInstanceNeeded, info.Value.ArrayNeeded); string commonCode = i.GenerateCommonCode(realClsName); ConstructorInfo[] ctors = info.Value.Constructors.ToArray(); string ctorRegisterCode = i.GenerateConstructorRegisterCode(ctors, excludeMethods); string methodWraperCode = i.GenerateMethodWraperCode(methods, realClsName, excludeMethods, valueTypeBinders, domain); string fieldWraperCode = fields.Length > 0 ? i.GenerateFieldWraperCode(fields, realClsName, excludeFields, valueTypeBinders, domain) : null; string cloneWraperCode = null; if (info.Value.ValueTypeNeeded) { //Memberwise clone should copy all fields var fs = i.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); cloneWraperCode = i.GenerateCloneWraperCode(fs, realClsName); } bool hasMethodCode = !string.IsNullOrEmpty(registerMethodCode); bool hasFieldCode = !string.IsNullOrEmpty(registerFieldCode); bool hasValueTypeCode = !string.IsNullOrEmpty(registerValueTypeCode); bool hasMiscCode = !string.IsNullOrEmpty(registerMiscCode); bool hasCtorCode = !string.IsNullOrEmpty(ctorRegisterCode); bool hasNormalMethod = methods.Where(x => !x.IsGenericMethod).Count() != 0; if ((hasMethodCode && hasNormalMethod) || hasFieldCode || hasCtorCode) sb.AppendLine(flagDef); if (hasMethodCode || hasCtorCode) sb.AppendLine(methodDef); if (hasFieldCode) sb.AppendLine(fieldDef); if (hasMethodCode || hasFieldCode || hasCtorCode) sb.AppendLine(argsDef); if (hasMethodCode || hasFieldCode || hasValueTypeCode || hasMiscCode || hasCtorCode) sb.AppendLine(typeDef); if (needMethods) sb.AppendLine(methodsDef); sb.AppendLine(registerMethodCode); if (fields.Length > 0) sb.AppendLine(registerFieldCode); if (info.Value.ValueTypeNeeded) sb.AppendLine(registerValueTypeCode); if (!string.IsNullOrEmpty(registerMiscCode)) sb.AppendLine(registerMiscCode); sb.AppendLine(ctorRegisterCode); sb.AppendLine(" }"); sb.AppendLine(); sb.AppendLine(commonCode); sb.AppendLine(methodWraperCode); if (fields.Length > 0) sb.AppendLine(fieldWraperCode); if (info.Value.ValueTypeNeeded) sb.AppendLine(cloneWraperCode); string ctorWraperCode = i.GenerateConstructorWraperCode(ctors, realClsName, excludeMethods, valueTypeBinders); sb.AppendLine(ctorWraperCode); sb.AppendLine(" }"); sb.AppendLine("}"); sw.Write(Regex.Replace(sb.ToString(), "(? /// Initialize the CLR binding, please invoke this AFTER CLR Redirection registration /// public static void Initialize(ILRuntime.Runtime.Enviorment.AppDomain app) {"); foreach (var i in clsNames) { sb.Append(" "); sb.Append(i); sb.AppendLine(".Register(app);"); } sb.AppendLine(@" } } }"); sw.Write(Regex.Replace(sb.ToString(), "(? 0 && !method.IsGenericInstance) continue; var body = method.Body; } } } } } internal static void CrawlAppdomain(ILRuntime.Runtime.Enviorment.AppDomain domain, Dictionary infos) { domain.SuppressStaticConstructor = true; //Prewarm PrewarmDomain(domain); //Prewarm twice to ensure GenericMethods are prewarmed properly PrewarmDomain(domain); var arr = domain.LoadedTypes.Values.ToArray(); foreach (var type in arr) { if (type is CLR.TypeSystem.ILType) { if (type.TypeForCLR.IsByRef || type.HasGenericParameter) continue; var methods = type.GetMethods().ToList(); foreach (var i in ((CLR.TypeSystem.ILType)type).GetConstructors()) methods.Add(i); if (((CLR.TypeSystem.ILType)type).GetStaticConstroctor() != null) methods.Add(((CLR.TypeSystem.ILType)type).GetStaticConstroctor()); foreach (var j in methods) { CLR.Method.ILMethod method = j as CLR.Method.ILMethod; if (method != null) { if (method.GenericParameterCount > 0 && !method.IsGenericInstance) continue; var body = method.Body; foreach (var ins in body) { switch (ins.Code) { case Intepreter.OpCodes.OpCodeEnum.Newobj: { CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod; if (m != null) { if (m.DeclearingType.IsDelegate) continue; Type t = m.DeclearingType.TypeForCLR; CLRBindingGenerateInfo info; if (!infos.TryGetValue(t, out info)) { info = CreateNewBindingInfo(t); infos[t] = info; } if (m.IsConstructor) info.Constructors.Add(m.ConstructorInfo); else info.Methods.Add(m.MethodInfo); } } break; case Intepreter.OpCodes.OpCodeEnum.Ldfld: case Intepreter.OpCodes.OpCodeEnum.Stfld: case Intepreter.OpCodes.OpCodeEnum.Ldflda: case Intepreter.OpCodes.OpCodeEnum.Ldsfld: case Intepreter.OpCodes.OpCodeEnum.Ldsflda: case Intepreter.OpCodes.OpCodeEnum.Stsfld: { var t = domain.GetType((int)(ins.TokenLong >> 32)) as CLR.TypeSystem.CLRType; if(t != null) { var fi = t.GetField((int)ins.TokenLong); if (fi != null && fi.IsPublic) { CLRBindingGenerateInfo info; if (!infos.TryGetValue(t.TypeForCLR, out info)) { info = CreateNewBindingInfo(t.TypeForCLR); infos[t.TypeForCLR] = info; } if (ins.Code == Intepreter.OpCodes.OpCodeEnum.Stfld || ins.Code == Intepreter.OpCodes.OpCodeEnum.Stsfld) { if (t.IsValueType) { info.ValueTypeNeeded = true; info.DefaultInstanceNeeded = true; } } info.Fields.Add(fi); } } } break; case Intepreter.OpCodes.OpCodeEnum.Ldtoken: { if (ins.TokenInteger == 0) { var t = domain.GetType((int)(ins.TokenLong >> 32)) as CLR.TypeSystem.CLRType; if (t != null) { var fi = t.GetField((int)ins.TokenLong); if (fi != null) { CLRBindingGenerateInfo info; if (!infos.TryGetValue(t.TypeForCLR, out info)) { info = CreateNewBindingInfo(t.TypeForCLR); infos[t.TypeForCLR] = info; } info.Fields.Add(fi); } } } } break; case Intepreter.OpCodes.OpCodeEnum.Newarr: { var t = domain.GetType(ins.TokenInteger) as CLR.TypeSystem.CLRType; if(t != null) { CLRBindingGenerateInfo info; if (!infos.TryGetValue(t.TypeForCLR, out info)) { info = CreateNewBindingInfo(t.TypeForCLR); infos[t.TypeForCLR] = info; } info.ArrayNeeded = true; } } break; case Intepreter.OpCodes.OpCodeEnum.Call: case Intepreter.OpCodes.OpCodeEnum.Callvirt: { CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod; if (m != null) { //Cannot explicit call base class's constructor directly if (m.IsConstructor && m.DeclearingType.CanAssignTo(((CLR.TypeSystem.ILType)type).FirstCLRBaseType)) continue; if (m.IsConstructor) { if (!m.ConstructorInfo.IsPublic) continue; Type t = m.DeclearingType.TypeForCLR; CLRBindingGenerateInfo info; if (!infos.TryGetValue(t, out info)) { info = CreateNewBindingInfo(t); infos[t] = info; } info.Constructors.Add(m.ConstructorInfo); } else { if (!m.MethodInfo.IsPublic) continue; Type t = m.DeclearingType.TypeForCLR; CLRBindingGenerateInfo info; if (!infos.TryGetValue(t, out info)) { info = CreateNewBindingInfo(t); infos[t] = info; } info.Methods.Add(m.MethodInfo); } } } break; } } } } } } } internal static CLRBindingGenerateInfo CreateNewBindingInfo(Type t) { CLRBindingGenerateInfo info = new CLRBindingGenerateInfo(); info.Type = t; info.Methods = new HashSet(); info.Fields = new HashSet(); info.Constructors = new HashSet(); if (t.IsValueType) info.DefaultInstanceNeeded = true; return info; } internal static List GenerateDelegateBinding(List types, string outputPath) { if (types == null) types = new List(0); List clsNames = new List(); foreach (var i in types) { var mi = i.GetMethod("Invoke"); var miParameters = mi.GetParameters(); if (mi.ReturnType == typeof(void) && miParameters.Length == 0) continue; string clsName, realClsName, paramClsName, paramRealClsName; bool isByRef, paramIsByRef; i.GetClassName(out clsName, out realClsName, out isByRef); clsNames.Add(clsName); using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/" + clsName + ".cs", false, new UTF8Encoding(false))) { StringBuilder sb = new StringBuilder(); sb.Append(@"using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using ILRuntime.CLR.TypeSystem; using ILRuntime.CLR.Method; using ILRuntime.Runtime.Enviorment; using ILRuntime.Runtime.Intepreter; using ILRuntime.Runtime.Stack; using ILRuntime.Reflection; using ILRuntime.CLR.Utils; namespace ILRuntime.Runtime.Generated { unsafe class "); sb.AppendLine(clsName); sb.AppendLine(@" { public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app) {"); bool first = true; if (mi.ReturnType != typeof(void)) { sb.Append(" app.DelegateManager.RegisterFunctionDelegate<"); first = true; foreach (var j in miParameters) { if (first) { first = false; } else sb.Append(", "); j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef); sb.Append(paramRealClsName); } if (!first) sb.Append(", "); mi.ReturnType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef); sb.Append(paramRealClsName); sb.AppendLine("> ();"); } else { sb.Append(" app.DelegateManager.RegisterMethodDelegate<"); first = true; foreach (var j in miParameters) { if (first) { first = false; } else sb.Append(", "); j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef); sb.Append(paramRealClsName); } sb.AppendLine("> ();"); } sb.AppendLine(); sb.Append(" app.DelegateManager.RegisterDelegateConvertor<"); sb.Append(realClsName); sb.AppendLine(">((act) =>"); sb.AppendLine(" {"); sb.Append(" return new "); sb.Append(realClsName); sb.Append("(("); first = true; foreach (var j in miParameters) { if (first) { first = false; } else sb.Append(", "); sb.Append(j.Name); } sb.AppendLine(") =>"); sb.AppendLine(" {"); if (mi.ReturnType != typeof(void)) { sb.Append(" return ((Func<"); first = true; foreach (var j in miParameters) { if (first) { first = false; } else sb.Append(", "); j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef); sb.Append(paramRealClsName); } if (!first) sb.Append(", "); mi.ReturnType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef); sb.Append(paramRealClsName); } else { sb.Append(" ((Action<"); first = true; foreach (var j in miParameters) { if (first) { first = false; } else sb.Append(", "); j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef); sb.Append(paramRealClsName); } } sb.Append(">)act)("); first = true; foreach (var j in miParameters) { if (first) { first = false; } else sb.Append(", "); sb.Append(j.Name); } sb.AppendLine(");"); sb.AppendLine(" });"); sb.AppendLine(" });"); sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); sw.Write(Regex.Replace(sb.ToString(), "(? clsNames, List valueTypeBinders, string outputPath) { if (!System.IO.Directory.Exists(outputPath)) System.IO.Directory.CreateDirectory(outputPath); using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/CLRBindings.cs", false, new UTF8Encoding(false))) { StringBuilder sb = new StringBuilder(); sb.Append(@"using System; using System.Collections.Generic; using System.Reflection; namespace ILRuntime.Runtime.Generated { class CLRBindings { "); sb.Append(SmartBindText); if (valueTypeBinders != null) { sb.AppendLine(); foreach (var i in valueTypeBinders) { string clsName, realClsName; bool isByRef; i.GetClassName(out clsName, out realClsName, out isByRef); sb.AppendLine(string.Format(" internal static ILRuntime.Runtime.Enviorment.ValueTypeBinder<{0}> s_{1}_Binder = null;", realClsName, clsName)); } sb.AppendLine(); } sb.AppendLine(@" /// /// Initialize the CLR binding, please invoke this AFTER CLR Redirection registration /// public static void Initialize(ILRuntime.Runtime.Enviorment.AppDomain app) {"); if (clsNames != null) { foreach (var i in clsNames) { sb.Append(" "); sb.Append(i); sb.AppendLine(".Register(app);"); } } if (valueTypeBinders != null && valueTypeBinders.Count > 0) { sb.AppendLine(); sb.AppendLine(" ILRuntime.CLR.TypeSystem.CLRType __clrType = null;"); foreach (var i in valueTypeBinders) { string clsName, realClsName; bool isByRef; i.GetClassName(out clsName, out realClsName, out isByRef); sb.AppendLine(string.Format(" __clrType = (ILRuntime.CLR.TypeSystem.CLRType)app.GetType (typeof({0}));", realClsName)); sb.AppendLine(string.Format(" s_{0}_Binder = __clrType.ValueTypeBinder as ILRuntime.Runtime.Enviorment.ValueTypeBinder<{1}>;", clsName, realClsName)); } } sb.AppendLine(@" }"); sb.AppendLine(@" /// /// Release the CLR binding, please invoke this BEFORE ILRuntime Appdomain destroy /// public static void Shutdown(ILRuntime.Runtime.Enviorment.AppDomain app) {"); if (valueTypeBinders != null) { foreach (var i in valueTypeBinders) { string clsName, realClsName; bool isByRef; i.GetClassName(out clsName, out realClsName, out isByRef); sb.AppendLine(string.Format(" s_{0}_Binder = null;", clsName)); } } sb.AppendLine(@" }"); sb.AppendLine(@" } }"); sw.Write(Regex.Replace(sb.ToString(), "(?