private static void RenderProviderGetter(StringWriter rw, InjectionSpecificationInjection injection, EmittedKernelSpec spec) { if (injection.Singleton) { rw.WriteLine("static {0}() {{", injection.ConcreteClassName); rw.WriteLine("{0} = new Lazy<{1}>(() => {{", spec.PrivateFieldName, spec.PrivateFieldType); } else { rw.WriteLine("{0} static {1} Get() {{", _renderAccessModifier, spec.ReturnType); } rw.WriteLine("var x = new {0}().Create();", injection.Provider); rw.WriteLine("return x;"); if (injection.Singleton) { rw.WriteLine("});"); rw.WriteLine("}"); rw.WriteLine("{0} static {1} Get() {{ return {2}.Value; }}", _renderAccessModifier, spec.ReturnType, spec.PrivateFieldName); rw.WriteLine("{0} static Lazy<{1}> GetLazy() {{ return {2}; }}", _renderAccessModifier, spec.ReturnType, spec.PrivateFieldName); } else { rw.WriteLine("}"); rw.WriteLine("{0} static Lazy<{1}> GetLazy() {{ return new Lazy<{1}>(Get); }}", _renderAccessModifier, spec.ReturnType); } }
private static void RenderClearAndRebind(StringWriter rw, EmittedKernelSpec spec) { rw.WriteLine("{0} static void Clear() {{ {2} = new Lazy<{1}>(() => null); }}", _renderAccessModifier, spec.PrivateFieldType, spec.PrivateFieldName); rw.WriteLine("{0} static void Rebind({1} value) {{ {2} = new Lazy<{1}>(() => value); }}", _renderAccessModifier, spec.PrivateFieldType, spec.PrivateFieldName); }
private static void AddRenderedKernel(EmittedKernelSpec spec, InjectionSpecificationInjection injection) { spec.Namespaces = CalculateNamespacesForInjection(injection); spec.Namespaces = spec.Namespaces.Distinct().ToList(); if (RenderedKernels.ContainsKey(spec.KernelClassName)) { throw new InvalidOperationException("Not unique?"); } RenderedKernels.Add(spec.KernelClassName, spec); }
private static string RenderPrivateField(StringWriter rw, EmittedKernelSpec spec, bool singleton) { int indexOf = spec.KernelClassName.IndexOf('_'); string fieldName = spec.KernelClassName.Remove(0, indexOf); if (singleton) { rw.WriteLine("private static Lazy<{0}> {1};", spec.PrivateFieldType, fieldName); } else { rw.WriteLine("private static {0} {1};", spec.PrivateFieldType, fieldName); } return(fieldName); }
private static void RenderConcreteBuilderGetter(StringWriter rw, InjectionSpecificationInjection injection, EmittedKernelSpec spec) { if (!string.IsNullOrEmpty(injection.Provider)) { throw new ParseException("Injection concrete '{0}' alse has provider '{1}' defined", injection.Concrete, injection.Provider); } string concreteToBuild = injection.Concrete; CSharpFile fileDefinition = injection.NoScan ? new CSharpFile(concreteToBuild) : FileScan(concreteToBuild, true); if (injection.Singleton) { rw.WriteLine("static {0}() {{", injection.ConcreteClassName); rw.WriteLine("{0} = new Lazy<{1}>(() => {{", spec.PrivateFieldName, spec.PrivateFieldType); } else { rw.WriteLine("{0} static {1} Get() {{", _renderAccessModifier, spec.ReturnType); } // There is no StackTrace on Metro :-( if (!_inputTokens.Contains("NETFX_CORE")) { if (!spec.IsDebug) { rw.WriteLine("#if DEBUG"); } rw.WriteLine("var stack = new StackTrace().GetFrames();"); rw.WriteLine("var methodName = stack.First().GetMethod().DeclaringType.Name;"); rw.WriteLine("if (stack.Count(y => y.GetMethod().DeclaringType.Name == methodName) > 2) { throw new Exception(\"Infinite loop detected\"); }"); if (!spec.IsDebug) { rw.WriteLine("#endif"); } } if (_benchmarking) { if (!spec.IsDebug) { rw.WriteLine("#if DEBUG"); } rw.WriteLine("Debug.WriteLine(\"Thread(\" + System.Threading.Thread.CurrentThread.ManagedThreadId + \") : Kernel TypeConstruct: {0}\");", injection.ConcreteClassName); rw.WriteLine("var stopWatch = System.Diagnostics.Stopwatch.StartNew();"); if (!spec.IsDebug) { rw.WriteLine("#endif"); } } rw.WriteLine("var x = new {0}(", concreteToBuild); if (injection.ConstructorArgument != null && injection.ConstructorArgument.Length > 0) { InjectionSpecificationInjectionConstructorArgument[] cArgs = injection.ConstructorArgument; for (int i = 0; i < cArgs.Length; i++) { if (i != 0) { rw.Write(','); } rw.WriteLine(injection.ConstructorArgument[i].Value); } } else { IList <string> cArgs = fileDefinition.ConstructorArgs ?? new List <string>(); for (int i = 0; i < cArgs.Count; i++) { if (i != 0) { rw.Write(','); } string interfaceRequired = cArgs[i]; string concreteFunction = GetConcreteYieldingFunction(interfaceRequired); rw.WriteLine(concreteFunction); } } rw.WriteLine(");"); if (_benchmarking) { if (!spec.IsDebug) { rw.WriteLine("#if DEBUG"); } rw.WriteLine("stopWatch.Stop();"); rw.WriteLine("Debug.WriteLine(\"Thread(\" + System.Threading.Thread.CurrentThread.ManagedThreadId + \") : Kernel TypeConstruct: {0}, MillisecondsElapsed: \" + stopWatch.ElapsedMilliseconds);", injection.ConcreteClassName); if (!spec.IsDebug) { rw.WriteLine("#endif"); } } if (!injection.NoScan) { if (_benchmarking) { if (!spec.IsDebug) { rw.WriteLine("#if DEBUG"); } rw.WriteLine("stopWatch = System.Diagnostics.Stopwatch.StartNew();"); if (!spec.IsDebug) { rw.WriteLine("#endif"); } } var hasProperties = RenderPropertyInjections(rw, fileDefinition); if (_benchmarking) { if (!spec.IsDebug) { rw.WriteLine("#if DEBUG"); } rw.WriteLine("stopWatch.Stop();"); if (hasProperties) { rw.WriteLine("Debug.WriteLine(\"Thread(\" + System.Threading.Thread.CurrentThread.ManagedThreadId + \") : Kernel TypePropertiesSet: {0}, MillisecondsElapsed: \" + stopWatch.ElapsedMilliseconds);", injection.ConcreteClassName); } if (!spec.IsDebug) { rw.WriteLine("#endif"); } } } rw.WriteLine("return x;"); if (injection.Singleton) { rw.WriteLine("});"); rw.WriteLine("}"); rw.WriteLine("{0} static {1} Get() {{ return {2}.Value; }}", _renderAccessModifier, spec.ReturnType, spec.PrivateFieldName); rw.WriteLine("{0} static Lazy<{1}> GetLazy() {{ return {2}; }}", _renderAccessModifier, spec.ReturnType, spec.PrivateFieldName); } else { rw.WriteLine("}"); rw.WriteLine("{0} static Lazy<{1}> GetLazy() {{ return new Lazy<{1}>(Get); }}", _renderAccessModifier, spec.ReturnType, spec.PrivateFieldName); } }
private static void Render(StringWriter rw, InjectionSpecificationInjection injection) { if (injection == null) { throw new ArgumentNullException("injection"); } bool debugEmit = injection.DebugOnly; if (debugEmit) { rw.WriteLine("#if DEBUG"); } string outerKernelClassName = injection.ConcreteClassName; var spec = new EmittedKernelSpec { KernelClassName = outerKernelClassName, IsDebug = injection.DebugOnly, Singleton = injection.Singleton }; rw.WriteLine("[CoverageExclude]"); rw.WriteLine("{0} static class {1} {{", _renderAccessModifier, outerKernelClassName); if (!string.IsNullOrEmpty(injection.Provider)) { if (injection.Interface.Length == 1) { spec.PrivateFieldType = injection.Interface.First().Value; } else { if (string.IsNullOrEmpty(injection.Concrete)) { throw new Exception("Providers with no concrete and interfaces.Count != 1 not supported"); } spec.PrivateFieldType = injection.Concrete; } if (injection.Singleton) { spec.PrivateFieldName = RenderPrivateField(rw, spec, injection.Singleton); } spec.ReturnType = injection.Interface != null && injection.Interface.Length == 1 ? injection.Interface.First().Value : injection.Concrete; RenderProviderGetter(rw, injection, spec); if (injection.Singleton) { RenderClearAndRebind(rw, spec); } } else if (!string.IsNullOrEmpty(injection.Concrete)) { spec.PrivateFieldType = injection.Interface != null && injection.Interface.Length == 1 ? injection.Interface.First().Value : injection.Concrete; spec.ReturnType = spec.PrivateFieldType; if (injection.Singleton) { spec.PrivateFieldName = RenderPrivateField(rw, spec, injection.Singleton); } RenderConcreteBuilderGetter(rw, injection, spec); if (injection.Singleton) { RenderClearAndRebind(rw, spec); } } else { throw new ParseException("Injection defined with no Concrete or Provider?"); } rw.WriteLine('}'); AddRenderedKernel(spec, injection); // Render additional interfaces... if (injection.Interface != null) { foreach (InjectionSpecificationInjectionInterface @interface in injection.Interface) { string interfaceName = @interface.Value; if (!interfaceName.StartsWith("I")) { throw new ParseException( string.Format( "All interfaces need to start with 'I'. Check the InjectionSpecification is formated correctly without line breaks or similare in the node. Current interface name being read: '{0}'.", interfaceName)); } string interfaceNameNoI = interfaceName.Substring(1, interfaceName.Length - 1).RemoveDodgyTokens(); EmittedKernelSpec existingSpec = RenderedKernels.Where(x => x.Value.ReturnType == interfaceName).Select(x => x.Value). SingleOrDefault(); if (!injection.ShouldHaveConcreteCoreRender && existingSpec != null) { // We've already built this above... continue; } // Render Kernel Reference which points to the concrete... var spec2 = new EmittedKernelSpec { KernelClassName = string.Format("Kernel_{0}", interfaceNameNoI), PrivateFieldType = interfaceName, IsDebug = false, Singleton = injection.Singleton }; rw.WriteLine("[CoverageExclude]"); rw.WriteLine("{0} static class {1} {{", _renderAccessModifier, spec2.KernelClassName); spec2.ReturnType = spec2.PrivateFieldType; if (injection.Singleton) { spec2.PrivateFieldName = RenderPrivateField(rw, spec2, injection.Singleton); rw.WriteLine( "static {0}() {{ {1} = new Lazy<{2}>({3}.Get); }}", spec2.KernelClassName, spec2.PrivateFieldName, spec2.ReturnType, injection.ConcreteClassName); rw.WriteLine( "{0} static {1} Get() {{ return {2}.Value; }}", _renderAccessModifier, spec2.ReturnType, spec2.PrivateFieldName); rw.WriteLine( "{0} static Lazy<{1}> GetLazy() {{ return {2}; }}", _renderAccessModifier, spec2.ReturnType, spec2.PrivateFieldName); RenderClearAndRebind(rw, spec2); } else { rw.WriteLine( "{0} static {1} Get() {{ return {3}.Get(); }}", _renderAccessModifier, spec2.ReturnType, spec2.PrivateFieldName, injection.ConcreteClassName); rw.WriteLine( "{0} static Lazy<{1}> GetLazy() {{ return new Lazy<{1}>({2}.Get); }}", _renderAccessModifier, spec2.ReturnType, injection.ConcreteClassName); } rw.WriteLine('}'); AddRenderedKernel(spec2, injection); } } if (debugEmit) { rw.WriteLine("#endif"); } }
private static void RenderNamespaces(StreamWriter rw) { var namespaces = new List <string>(); var debugNamespaces = new List <string>(); namespaces.Add("System"); namespaces.Add("System.Diagnostics"); namespaces.Add("System.Linq"); namespaces.Add("System.Reflection"); foreach (string kernelKey in RenderedKernels.Keys) { EmittedKernelSpec kernel = RenderedKernels[kernelKey]; foreach (string @namespace in kernel.Namespaces) { if (kernel.IsDebug) { debugNamespaces.Add(@namespace); } else { namespaces.Add(@namespace); } } } // Add explicit namespaces if (_injectionSpecification.Namespaces != null) { foreach (InjectionSpecificationNamespace explicitNamespace in _injectionSpecification.Namespaces) { string condition = explicitNamespace.Condition; bool valid = true; if (!String.IsNullOrEmpty(condition)) { bool invertCondition = false; if (condition.StartsWith("!")) { invertCondition = true; condition = condition.Substring(1, condition.Length - 1); } valid = _inputTokens.Contains(condition) != invertCondition; } if (valid) { if (explicitNamespace.DebugOnlySpecified && explicitNamespace.DebugOnly) { debugNamespaces.Add(explicitNamespace.Value); } else { namespaces.Add(explicitNamespace.Value); } } } } // Filter and sort namespaces = namespaces.Distinct().OrderBy(x => x).ToList(); debugNamespaces = debugNamespaces.Where(x => !namespaces.Contains(x)).Distinct().OrderBy(x => x).ToList(); if (debugNamespaces.Count > 0) { rw.WriteLine("#if DEBUG"); } foreach (string @namespace in debugNamespaces) { rw.WriteLine("using {0};", @namespace); } if (debugNamespaces.Count > 0) { rw.WriteLine("#endif"); } foreach (string @namespace in namespaces) { rw.WriteLine("using {0};", @namespace); } }
private static void RenderProviderGetter(StringWriter rw, InjectionSpecificationInjection injection, EmittedKernelSpec spec) { rw.WriteLine("{0} static {1} Get() {{", _renderAccessModifier, spec.ReturnType); if (injection.Singleton) { rw.WriteLine("if({0} != null) return {0};", spec.PrivateFieldName); } rw.WriteLine("{0} = new {1}().Create();", spec.PrivateFieldName, injection.Provider); rw.WriteLine("return {0};", spec.PrivateFieldName); rw.WriteLine("}"); }
private static string RenderPrivateField(StringWriter rw, EmittedKernelSpec spec) { int indexOf = spec.KernelClassName.IndexOf('_'); string fieldName = spec.KernelClassName.Remove(0, indexOf); rw.WriteLine("private static {0} {1};", spec.PrivateFieldType, fieldName); return fieldName; }
private static void RenderConcreteBuilderGetter(StringWriter rw, InjectionSpecificationInjection injection, EmittedKernelSpec spec) { if (!string.IsNullOrEmpty(injection.Provider)) { throw new ParseException("Injection concrete '{0}' alse has provider '{1}' defined", injection.Concrete, injection.Provider); } string concreteToBuild = injection.Concrete; CSharpFile fileDefinition = injection.NoScan ? new CSharpFile(concreteToBuild) : FileScan(concreteToBuild, true); rw.WriteLine("{0} static {1} Get() {{", _renderAccessModifier, spec.ReturnType); if (injection.Singleton) { rw.WriteLine("if({0} != null) return {0};", spec.PrivateFieldName); } // There is no StackTrace on Metro :-( if (!_inputTokens.Contains("NETFX_CORE")) { if (!spec.IsDebug) { rw.WriteLine("#if DEBUG"); } rw.WriteLine("var stack = new StackTrace().GetFrames();"); rw.WriteLine("var methodName = stack.First().GetMethod().DeclaringType.Name;"); rw.WriteLine( "if (stack.Count(y => y.GetMethod().DeclaringType.Name == methodName) > 1) { throw new Exception(\"Infinite loop detected\"); }"); if (!spec.IsDebug) { rw.WriteLine("#endif"); } } rw.WriteLine("var x = new {0}(", concreteToBuild); if (injection.ConstructorArgument != null && injection.ConstructorArgument.Length > 0) { InjectionSpecificationInjectionConstructorArgument[] cArgs = injection.ConstructorArgument; for (int i = 0; i < cArgs.Length; i++) { if (i != 0) { rw.Write(','); } rw.WriteLine(injection.ConstructorArgument[i].Value); } } else { IList<string> cArgs = fileDefinition.ConstructorArgs ?? new List<string>(); for (int i = 0; i < cArgs.Count; i++) { if (i != 0) { rw.Write(','); } string interfaceRequired = cArgs[i]; string concreteFunction = GetConcreteYieldingFunction(interfaceRequired); rw.WriteLine(concreteFunction); } } rw.WriteLine(");"); rw.WriteLine("{0} = x;", spec.PrivateFieldName); if (!injection.NoScan) { RenderPropertyInjections(rw, fileDefinition); } rw.WriteLine("return {0};", spec.PrivateFieldName); rw.WriteLine("}"); }
private static void RenderClearAndRebind(StringWriter rw, EmittedKernelSpec spec) { // Annoyingly, I wanted to do these through reflection to ensure encapsulation, but silverlight has removed the // ability to assign private fields, so I'm forced to make these public... rw.WriteLine("{0} static void Clear() {{ {1} = null; }}", _renderAccessModifier, spec.PrivateFieldName); rw.WriteLine("{0} static void Rebind({1} value) {{ {2} = value; }}", _renderAccessModifier, spec.PrivateFieldType, spec.PrivateFieldName); }
private static void Render(StringWriter rw, InjectionSpecificationInjection injection) { if (injection == null) { throw new ArgumentNullException("injection"); } bool debugEmit = injection.DebugOnly; if (debugEmit) { rw.WriteLine("#if DEBUG"); } string outerKernelClassName = injection.ConcreteClassName; var spec = new EmittedKernelSpec { KernelClassName = outerKernelClassName, IsDebug = injection.DebugOnly }; rw.WriteLine("[CoverageExclude]"); rw.WriteLine("{0} static class {1} {{", _renderAccessModifier, outerKernelClassName); RenderStaticConstructorDebugLog(injection, debugEmit, rw); if (!string.IsNullOrEmpty(injection.Provider)) { if (string.IsNullOrEmpty(injection.Concrete)) { if (injection.Interface.Count() != 1) { throw new Exception("Providers with no concrete and interfaces.Count != 1 not supported"); } spec.PrivateFieldType = injection.Interface.First().Value; spec.PrivateFieldName = RenderPrivateField(rw, spec); } else { spec.PrivateFieldType = injection.Concrete; spec.PrivateFieldName = RenderPrivateField(rw, spec); } spec.ReturnType = injection.Interface != null && injection.Interface.Length == 1 ? injection.Interface.First().Value : injection.Concrete; RenderProviderGetter(rw, injection, spec); RenderClearAndRebind(rw, spec); } else if (!string.IsNullOrEmpty(injection.Concrete)) { spec.PrivateFieldType = injection.Interface != null && injection.Interface.Length == 1 ? injection.Interface.First().Value : injection.Concrete; spec.ReturnType = spec.PrivateFieldType; spec.PrivateFieldName = RenderPrivateField(rw, spec); RenderConcreteBuilderGetter(rw, injection, spec); RenderClearAndRebind(rw, spec); } else { throw new ParseException("Injection defined with no Concrete or Provider?"); } rw.WriteLine('}'); AddRenderedKernel(spec, injection); // Render additional interfaces... if (injection.Interface != null) { foreach (InjectionSpecificationInjectionInterface @interface in injection.Interface) { string interfaceName = @interface.Value; if (!interfaceName.StartsWith("I")) { throw new ParseException( string.Format( "All interfaces need to start with 'I'. Check the InjectionSpecification is formated correctly without line breaks or similare in the node. Current interface name being read: '{0}'.", interfaceName)); } string interfaceNameNoI = interfaceName.Substring(1, interfaceName.Length - 1).RemoveDodgyTokens(); EmittedKernelSpec existingSpec = RenderedKernels.Where(x => x.Value.ReturnType == interfaceName).Select(x => x.Value). SingleOrDefault(); if (!injection.ShouldHaveConcreteCoreRender && existingSpec != null) { // We've already built this above... continue; } // Render Kernel Reference which points to the concrete... var spec2 = new EmittedKernelSpec { KernelClassName = string.Format("Kernel_{0}", interfaceNameNoI), PrivateFieldType = interfaceName, IsDebug = false }; rw.WriteLine("[CoverageExclude]"); rw.WriteLine("{0} static class {1} {{", _renderAccessModifier, spec2.KernelClassName); spec2.PrivateFieldName = RenderPrivateField(rw, spec2); spec2.ReturnType = spec2.PrivateFieldType; rw.WriteLine( "{0} static {1} Get() {{ if({2} != null) {{ return {2}; }} var x = {3}.Get(); {2} = x; return x; }}", _renderAccessModifier, spec2.ReturnType, spec2.PrivateFieldName, injection.ConcreteClassName); RenderClearAndRebind(rw, spec2); rw.WriteLine('}'); AddRenderedKernel(spec2, injection); } } if (debugEmit) { rw.WriteLine("#endif"); } }