From: <jer...@us...> - 2009-01-03 00:07:37
|
Revision: 214 http://structuremap.svn.sourceforge.net/structuremap/?rev=214&view=rev Author: jeremydmiller Date: 2009-01-03 00:07:32 +0000 (Sat, 03 Jan 2009) Log Message: ----------- Missing Instance, BuildUp, documentation, conditional instance Modified Paths: -------------- trunk/Docs/style.css trunk/Source/CommonAssemblyInfo.cs trunk/Source/StructureMap/BuildSession.cs trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs trunk/Source/StructureMap/Configuration/DSL/Expressions/InstanceExpression.cs trunk/Source/StructureMap/Configuration/DSL/Registry.cs trunk/Source/StructureMap/ConfigurationExpression.cs trunk/Source/StructureMap/Container.cs trunk/Source/StructureMap/Emitting/ArgumentEmitter.cs trunk/Source/StructureMap/Emitting/BuildInstanceMethod.cs trunk/Source/StructureMap/Emitting/InstanceBuilderAssembly.cs trunk/Source/StructureMap/Emitting/Parameters/ParameterEmitter.cs trunk/Source/StructureMap/ExplicitArgsExpression.cs trunk/Source/StructureMap/Graph/Constructor.cs trunk/Source/StructureMap/Graph/Plugin.cs trunk/Source/StructureMap/Graph/PluginCache.cs trunk/Source/StructureMap/Graph/PluginFamily.cs trunk/Source/StructureMap/Graph/SetterPropertyCollection.cs trunk/Source/StructureMap/IContainer.cs trunk/Source/StructureMap/IInstanceFactory.cs trunk/Source/StructureMap/InitializationExpression.cs trunk/Source/StructureMap/InstanceBuilder.cs trunk/Source/StructureMap/InstanceFactory.cs trunk/Source/StructureMap/ObjectFactory.cs trunk/Source/StructureMap/Pipeline/BuildFrame.cs trunk/Source/StructureMap/ReflectionHelper.cs trunk/Source/StructureMap/StructureMap.csproj trunk/Source/StructureMap/SystemRegistry.cs trunk/Source/StructureMap.Testing/Configuration/DSL/AddInstanceTester.cs trunk/Source/StructureMap.Testing/Configuration/DSL/CreatePluginFamilyTester.cs trunk/Source/StructureMap.Testing/Configuration/DSL/GenericFamilyExpressionTester.cs trunk/Source/StructureMap.Testing/Examples/RegisteringWithTheAPI.cs trunk/Source/StructureMap.Testing/Examples.cs trunk/Source/StructureMap.Testing/Graph/ContainerTester.cs trunk/Source/StructureMap.Testing/Graph/InstanceFactoryTester.cs trunk/Source/StructureMap.Testing/Graph/PluginTester.cs trunk/Source/StructureMap.Testing/Graph/TestExplicitArguments.cs trunk/Source/StructureMap.Testing/Pipeline/OptionalSetterInjectionTester.cs trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj trunk/Source/StructureMap.Testing.Widget/BuilderSamples.cs trunk/Source/StructureMap.Testing.Widget3/IService.cs trunk/cruise.build Added Paths: ----------- trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs trunk/Source/StructureMap/Emitting/BuildUpMethod.cs trunk/Source/StructureMap/Pipeline/ConditionalInstance.cs trunk/Source/StructureMap.Testing/AutoWiringExamples.cs trunk/Source/StructureMap.Testing/Bugs/SingletonShouldBeLazy.cs trunk/Source/StructureMap.Testing/BuildUpIntegratedTester.cs trunk/Source/StructureMap.Testing/BuildUpTester.cs trunk/Source/StructureMap.Testing/Configuration/DSL/ProgrammaticConstructorSelectionTester.cs trunk/Source/StructureMap.Testing/Examples/CustomInstance.cs trunk/Source/StructureMap.Testing/Graph/ConventionBasedSetterInjectionTester.cs trunk/Source/StructureMap.Testing/Pipeline/ConditionalInstanceTester.cs trunk/Source/StructureMap.Testing/Pipeline/MissingInstanceTester.cs trunk/Source/StructureMap.Testing/PrimitiveArrayTester.cs Modified: trunk/Docs/style.css =================================================================== --- trunk/Docs/style.css 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Docs/style.css 2009-01-03 00:07:32 UTC (rev 214) @@ -16,7 +16,8 @@ } H2 { - COLOR: #316592; + BACKGROUND-COLOR: #316592; + COLOR: white; FONT-FAMILY: Arial; FONT-SIZE: large; FONT-WEIGHT: bold; Modified: trunk/Source/CommonAssemblyInfo.cs =================================================================== --- trunk/Source/CommonAssemblyInfo.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/CommonAssemblyInfo.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -5,7 +5,7 @@ //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. -// Runtime Version:2.0.50727.1434 +// Runtime Version:2.0.50727.3053 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. Modified: trunk/Source/StructureMap/BuildSession.cs =================================================================== --- trunk/Source/StructureMap/BuildSession.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/BuildSession.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -25,6 +25,24 @@ /// <typeparam name="T"></typeparam> /// <returns></returns> T GetInstance<T>(); + + /// <summary> + /// Gets the root "frame" of the object request + /// </summary> + BuildFrame Root { get; } + + /// <summary> + /// The requested instance name of the object graph + /// </summary> + string RequestedName { get; } + + /// <summary> + /// Register a default object for the given PluginType that will + /// be used throughout the rest of the current object request + /// </summary> + /// <param name="pluginType"></param> + /// <param name="defaultObject"></param> + void RegisterDefault(Type pluginType, object defaultObject); } public class BuildSession : IContext @@ -63,6 +81,8 @@ } + public string RequestedName { get; set; } + protected PipelineGraph pipelineGraph { get { return _pipelineGraph; } @@ -85,6 +105,11 @@ return (T) CreateInstance(typeof (T)); } + BuildFrame IContext.Root + { + get { return _buildStack.Root; } + } + #endregion public virtual object CreateInstance(Type pluginType, string name) @@ -112,6 +137,7 @@ return result; } + public virtual Array CreateInstanceArray(Type pluginType, Instance[] instances) { Array array; Modified: trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -38,6 +38,14 @@ get { return new InstanceExpression<PLUGINTYPE>(i => registerDefault(i)); } } + public InstanceExpression<PLUGINTYPE> MissingNamedInstanceIs + { + get + { + return new InstanceExpression<PLUGINTYPE>(i => _alterations.Add(family => family.MissingInstance = i)); + } + } + /// <summary> /// Add multiple Instance's to this PluginType /// </summary> Modified: trunk/Source/StructureMap/Configuration/DSL/Expressions/InstanceExpression.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Expressions/InstanceExpression.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Configuration/DSL/Expressions/InstanceExpression.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -28,6 +28,11 @@ LiteralInstance IsThis(T obj); } + public interface ThenItExpression<T> + { + IsExpression<T> ThenIt { get; } + } + /// <summary> /// An Expression Builder to define Instances of a PluginType. /// This is mostly used for configuring open generic types @@ -178,9 +183,17 @@ /// <param name="url"></param> /// <returns></returns> UserControlInstance LoadControlFrom(string url); + + /// <summary> + /// Creates an Instance according to conditional rules + /// </summary> + /// <param name="configuration"></param> + /// <returns></returns> + // Conditional object construction + ConditionalInstance<T> Conditional(Action<ConditionalInstance<T>.ConditionalInstanceExpression<T>> configuration); } - public class InstanceExpression<T> : IInstanceExpression<T> + public class InstanceExpression<T> : IInstanceExpression<T>, ThenItExpression<T> { private readonly Action<Instance> _action; @@ -268,5 +281,15 @@ { return returnInstance(new UserControlInstance(url)); } + + public ConditionalInstance<T> Conditional(Action<ConditionalInstance<T>.ConditionalInstanceExpression<T>> configuration) + { + return returnInstance(new ConditionalInstance<T>(configuration)); + } + + IsExpression<T> ThenItExpression<T>.ThenIt + { + get { return this; } + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/Configuration/DSL/Registry.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Registry.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Configuration/DSL/Registry.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -7,6 +7,37 @@ namespace StructureMap.Configuration.DSL { + public interface IRegistry + { + // Registering Types -- BuildInstancesOf() and ForRequestedType() are Synonyms + CreatePluginFamilyExpression<PLUGINTYPE> BuildInstancesOf<PLUGINTYPE>(); + CreatePluginFamilyExpression<PLUGINTYPE> ForRequestedType<PLUGINTYPE>(); + + GenericFamilyExpression ForRequestedType(Type pluginType); + + // Shortcut for configuring the default configuration of a concrete type + Registry.BuildWithExpression<T> ForConcreteType<T>(); + + // Adding additional Instances of a PluginType + IsExpression<T> InstanceOf<T>(); + GenericIsExpression InstanceOf(Type pluginType); + + // Creating or Adding to a Profile + ProfileExpression CreateProfile(string profileName); + void CreateProfile(string profileName, Action<ProfileExpression> action); + + // Interception + void RegisterInterceptor(TypeInterceptor interceptor); + MatchedTypeInterceptor IfTypeMatches(Predicate<Type> match); + + // Type Scanning and Auto Registration + void Scan(Action<IAssemblyScanner> action); + + // Controlling Setter Injection Behavior + CreatePluginFamilyExpression<PLUGINTYPE> FillAllPropertiesOfType<PLUGINTYPE>(); + void SetAllProperties(Action<SetterConvention> action); + } + /// <summary> /// A Registry class provides methods and grammars for configuring a Container or ObjectFactory. /// Using a Registry subclass is the recommended way of configuring a StructureMap Container. @@ -20,7 +51,7 @@ /// } /// } /// </example> - public class Registry + public class Registry : IRegistry { private readonly List<Action<PluginGraph>> _actions = new List<Action<PluginGraph>>(); private readonly List<Action> _basicActions = new List<Action>(); @@ -79,7 +110,6 @@ /// Scoping, the Default Instance, and interception. This method is specifically /// meant for registering open generic types /// </summary> - /// <typeparam name="PLUGINTYPE"></typeparam> /// <returns></returns> public GenericFamilyExpression ForRequestedType(Type pluginType) { @@ -182,6 +212,11 @@ internal static bool IsPublicRegistry(Type type) { + if (type.Assembly == typeof(Registry).Assembly) + { + return false; + } + if (!typeof (Registry).IsAssignableFrom(type)) { return false; @@ -291,5 +326,16 @@ } #endregion + + /// <summary> + /// Creates automatic "policies" for which public setters are considered mandatory + /// properties by StructureMap that will be "setter injected" as part of the + /// construction process. + /// </summary> + /// <param name="action"></param> + public void SetAllProperties(Action<SetterConvention> action) + { + action(new SetterConvention()); + } } } \ No newline at end of file Added: trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs (rev 0) +++ trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -0,0 +1,63 @@ +using System; +using System.Reflection; +using StructureMap.Graph; +using StructureMap; + +namespace StructureMap.Configuration.DSL +{ + /// <summary> + /// Used as an expression builder to specify setter injection policies + /// </summary> + public class SetterConvention + { + /// <summary> + /// Directs StructureMap to treat all public setters of type T as + /// mandatory properties + /// </summary> + /// <typeparam name="T"></typeparam> + public void OfType<T>() + { + Matching(prop => prop.PropertyType == typeof (T)); + } + + /// <summary> + /// Directs StructureMap to treat all public setters that match the + /// rule as mandatory properties + /// </summary> + /// <param name="rule"></param> + public void Matching(Predicate<PropertyInfo> rule) + { + PluginCache.UseSetterRule(rule); + } + + /// <summary> + /// Directs StructureMap to treat all public setters with a property + /// type in the specified namespace as mandatory properties + /// </summary> + /// <param name="nameSpace"></param> + public void WithAnyTypeFromNamespace(string nameSpace) + { + Matching(prop => prop.PropertyType.IsInNamespace(nameSpace)); + } + + /// <summary> + /// Directs StructureMap to treat all public setters with a property + /// type in the specified namespace as mandatory properties + /// </summary> + /// <typeparam name="T"></typeparam> + public void WithAnyTypeFromNamespaceContainingType<T>() + { + WithAnyTypeFromNamespace(typeof(T).Namespace); + } + + /// <summary> + /// Directs StructureMap to treat all public setters where to property name + /// matches the specified rule as a mandatory property + /// </summary> + /// <param name="rule"></param> + public void NameMatches(Predicate<string> rule) + { + Matching(prop => rule(prop.Name)); + } + } +} \ No newline at end of file Modified: trunk/Source/StructureMap/ConfigurationExpression.cs =================================================================== --- trunk/Source/StructureMap/ConfigurationExpression.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/ConfigurationExpression.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Linq.Expressions; using System.Xml; using StructureMap.Configuration; using StructureMap.Configuration.DSL; @@ -83,5 +85,20 @@ return builder.Build(); } + + /// <summary> + /// Use to programmatically select the constructor function of a concrete + /// class. Applies globally to all Containers in a single AppDomain. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func"></param> + public void SelectConstructor<T>(Expression<Func<T>> expression) + { + PluginCache.GetPlugin(typeof (T)).UseConstructor(expression); + } } + + + + } \ No newline at end of file Modified: trunk/Source/StructureMap/Container.cs =================================================================== --- trunk/Source/StructureMap/Container.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Container.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -40,7 +40,6 @@ /// </summary> /// <param name="pluginGraph">PluginGraph containing the instance and type definitions /// for the Container</param> - /// <param name="failOnException">Flags the Container to fail or trap exceptions</param> public Container(PluginGraph pluginGraph) { construct(pluginGraph); @@ -80,7 +79,6 @@ /// <summary> /// Creates a new instance of the requested type T using the supplied Instance. Mostly used internally /// </summary> - /// <param name="pluginType"></param> /// <param name="instance"></param> /// <returns></returns> public T GetInstance<T>(Instance instance) @@ -91,7 +89,6 @@ /// <summary> /// Gets the default instance of the pluginType using the explicitly configured arguments from the "args" /// </summary> - /// <param name="pluginType"></param> /// <param name="args"></param> /// <returns></returns> public PLUGINTYPE GetInstance<PLUGINTYPE>(ExplicitArguments args) @@ -117,7 +114,7 @@ BasicInstance basicInstance = defaultInstance as BasicInstance; Instance instance = basicInstance == null ? defaultInstance : new ExplicitInstance(pluginType, args, basicInstance); - BuildSession session = withNewSession(); + BuildSession session = withNewSession(Plugin.DEFAULT); args.RegisterDefaults(session); @@ -128,12 +125,12 @@ /// <summary> /// Gets all configured instances of type T using explicitly configured arguments from the "args" /// </summary> - /// <typeparam name="T"></typeparam> + /// <param name="type"></param> /// <param name="args"></param> /// <returns></returns> public IList GetAllInstances(Type type, ExplicitArguments args) { - BuildSession session = withNewSession(); + BuildSession session = withNewSession(Plugin.DEFAULT); args.RegisterDefaults(session); @@ -143,7 +140,7 @@ public IList<T> GetAllInstances<T>(ExplicitArguments args) { - BuildSession session = withNewSession(); + BuildSession session = withNewSession(Plugin.DEFAULT); args.RegisterDefaults(session); @@ -185,7 +182,7 @@ /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> - /// <param name="instance"></param> + /// <param name="stub"></param> public void Inject<T>(string name, T stub) { LiteralInstance instance = new LiteralInstance(stub).WithName(name); @@ -199,7 +196,7 @@ /// <returns></returns> public IList<T> GetAllInstances<T>() { - BuildSession session = withNewSession(); + BuildSession session = withNewSession(Plugin.DEFAULT); return getListOfTypeWithSession<T>(session); } @@ -220,7 +217,7 @@ /// <returns></returns> public object GetInstance(Type pluginType, string instanceKey) { - return withNewSession().CreateInstance(pluginType, instanceKey); + return withNewSession(instanceKey).CreateInstance(pluginType, instanceKey); } /// <summary> @@ -228,7 +225,6 @@ /// </summary> /// <param name="pluginType"></param> /// <param name="instanceKey"></param> - /// <param name="instance"></param> /// <returns></returns> public object TryGetInstance(Type pluginType, string instanceKey) { @@ -241,7 +237,6 @@ /// Creates or finds the default instance of the pluginType. Returns null if the pluginType is not known to the container. /// </summary> /// <param name="pluginType"></param> - /// <param name="instance"></param> /// <returns></returns> public object TryGetInstance(Type pluginType) { @@ -254,7 +249,6 @@ /// Creates or finds the default instance of type T. Returns the default value of T if it is not known to the container. /// </summary> /// <typeparam name="T"></typeparam> - /// <param name="instance"></param> /// <returns></returns> public T TryGetInstance<T>() { @@ -262,10 +256,25 @@ } /// <summary> + /// The "BuildUp" method takes in an already constructed object + /// and uses Setter Injection to push in configured dependencies + /// of that object + /// </summary> + /// <param name="target"></param> + public void BuildUp(object target) + { + var pluggedType = target.GetType(); + IConfiguredInstance instance = _pipelineGraph.GetDefault(pluggedType) as IConfiguredInstance + ?? new ConfiguredInstance(pluggedType); + + var builder = PluginCache.FindBuilder(pluggedType); + builder.BuildUp(instance, withNewSession(Plugin.DEFAULT), target); + } + + /// <summary> /// Creates or finds the named instance of type T. Returns the default value of T if the named instance is not known to the container. /// </summary> /// <typeparam name="T"></typeparam> - /// <param name="instance"></param> /// <returns></returns> public T TryGetInstance<T>(string instanceKey) { @@ -279,7 +288,7 @@ /// <returns></returns> public object GetInstance(Type pluginType) { - return withNewSession().CreateInstance(pluginType); + return withNewSession(Plugin.DEFAULT).CreateInstance(pluginType); } @@ -291,7 +300,7 @@ /// <returns></returns> public object GetInstance(Type pluginType, Instance instance) { - return withNewSession().CreateInstance(pluginType, instance); + return withNewSession(instance.Name).CreateInstance(pluginType, instance); } public void SetDefault(Type pluginType, Instance instance) @@ -343,7 +352,7 @@ /// <returns></returns> public IList GetAllInstances(Type pluginType) { - return forType(pluginType).GetAllInstances(withNewSession()); + return forType(pluginType).GetAllInstances(withNewSession(Plugin.DEFAULT)); } /// <summary> @@ -464,9 +473,9 @@ _pipelineGraph.SetDefault(pluginType, instance); } - private BuildSession withNewSession() + private BuildSession withNewSession(string name) { - return new BuildSession(_pipelineGraph, _interceptorLibrary); + return new BuildSession(_pipelineGraph, _interceptorLibrary){RequestedName = name}; } @@ -474,5 +483,7 @@ { return _pipelineGraph.ForType(type); } + + } } \ No newline at end of file Modified: trunk/Source/StructureMap/Emitting/ArgumentEmitter.cs =================================================================== --- trunk/Source/StructureMap/Emitting/ArgumentEmitter.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Emitting/ArgumentEmitter.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -13,11 +13,13 @@ private readonly PrimitiveParameterEmitter _primitive = new PrimitiveParameterEmitter(); private readonly StringParameterEmitter _string = new StringParameterEmitter(); private readonly ILGenerator ilgen; + private readonly bool _inConstructor = true; - public ArgumentEmitter(ILGenerator ilgen) + public ArgumentEmitter(ILGenerator ilgen, bool inConstructor) { this.ilgen = ilgen; + _inConstructor = inConstructor; } #region IArgumentVisitor Members @@ -82,7 +84,7 @@ } else { - emitter.OptionalSetter(ilgen, property); + emitter.OptionalSetter(ilgen, property, _inConstructor); } } } Modified: trunk/Source/StructureMap/Emitting/BuildInstanceMethod.cs =================================================================== --- trunk/Source/StructureMap/Emitting/BuildInstanceMethod.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Emitting/BuildInstanceMethod.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -47,7 +47,7 @@ ilgen.DeclareLocal(typeof (bool)); } - var arguments = new ArgumentEmitter(ilgen); + var arguments = new ArgumentEmitter(ilgen, true); _plugin.VisitConstructor(arguments); Added: trunk/Source/StructureMap/Emitting/BuildUpMethod.cs =================================================================== --- trunk/Source/StructureMap/Emitting/BuildUpMethod.cs (rev 0) +++ trunk/Source/StructureMap/Emitting/BuildUpMethod.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Text; +using StructureMap.Graph; +using StructureMap.Pipeline; + +namespace StructureMap.Emitting +{ + public class BuildUpMethod : Method + { + private readonly Plugin _plugin; + + public BuildUpMethod(Plugin plugin) + { + _plugin = plugin; + } + + public override string MethodName + { + get { return "BuildUp"; } + } + + public override Type[] ArgumentList + { + get { return new Type[] { typeof(IConfiguredInstance), typeof(BuildSession) , typeof(object)}; } + } + + public override Type ReturnType + { + get { return typeof(void); } + } + + protected override void Generate(ILGenerator ilgen) + { + ilgen.Emit(OpCodes.Nop); + + ilgen.DeclareLocal(_plugin.PluggedType); + ilgen.DeclareLocal(typeof(bool)); + + ilgen.Emit(OpCodes.Ldarg_3); + ilgen.Emit(OpCodes.Castclass, _plugin.PluggedType); + ilgen.Emit(OpCodes.Stloc_0); + + var arguments = new ArgumentEmitter(ilgen, false); + + _plugin.VisitSetters(arguments); + + ilgen.Emit(OpCodes.Ret); + + } + } +} Modified: trunk/Source/StructureMap/Emitting/InstanceBuilderAssembly.cs =================================================================== --- trunk/Source/StructureMap/Emitting/InstanceBuilderAssembly.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Emitting/InstanceBuilderAssembly.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -88,8 +88,11 @@ { builderClass.AddPluggedTypeGetter(plugin.PluggedType); - var method = new BuildInstanceMethod(plugin); - builderClass.AddMethod(method); + var buildInstanceMethod = new BuildInstanceMethod(plugin); + builderClass.AddMethod(buildInstanceMethod); + + var buildUpMethod = new BuildUpMethod(plugin); + builderClass.AddMethod(buildUpMethod); } } } \ No newline at end of file Modified: trunk/Source/StructureMap/Emitting/Parameters/ParameterEmitter.cs =================================================================== --- trunk/Source/StructureMap/Emitting/Parameters/ParameterEmitter.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Emitting/Parameters/ParameterEmitter.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -29,24 +29,30 @@ public abstract void MandatorySetter(ILGenerator ilgen, PropertyInfo property); - public void OptionalSetter(ILGenerator ilgen, PropertyInfo property) + public void OptionalSetter(ILGenerator ilgen, PropertyInfo property, bool inConstructor) { ilgen.Emit(OpCodes.Ldarg_1); ilgen.Emit(OpCodes.Ldstr, property.Name); ilgen.Emit(OpCodes.Callvirt, Methods.HAS_PROPERTY); ilgen.Emit(OpCodes.Ldc_I4_0); ilgen.Emit(OpCodes.Ceq); - ilgen.Emit(OpCodes.Stloc_2); - ilgen.Emit(OpCodes.Ldloc_2); + if (inConstructor) + { + ilgen.Emit(OpCodes.Stloc_2); + ilgen.Emit(OpCodes.Ldloc_2); + } + else + { + ilgen.Emit(OpCodes.Stloc_1); + ilgen.Emit(OpCodes.Ldloc_1); + } + + Label label = ilgen.DefineLabel(); - ilgen.Emit(OpCodes.Brtrue_S, label); - MandatorySetter(ilgen, property); - ilgen.Emit(OpCodes.Nop); - ilgen.MarkLabel(label); } } Modified: trunk/Source/StructureMap/ExplicitArgsExpression.cs =================================================================== --- trunk/Source/StructureMap/ExplicitArgsExpression.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/ExplicitArgsExpression.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -85,7 +85,6 @@ /// Gets all configured instances of type T using explicitly configured arguments /// </summary> /// <typeparam name="T"></typeparam> - /// <param name="args"></param> /// <returns></returns> public IList<T> GetAllInstances<T>() { Modified: trunk/Source/StructureMap/Graph/Constructor.cs =================================================================== --- trunk/Source/StructureMap/Graph/Constructor.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Graph/Constructor.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -1,11 +1,12 @@ using System; +using System.Linq.Expressions; using System.Reflection; namespace StructureMap.Graph { public class Constructor : TypeRules { - private readonly ConstructorInfo _ctor; + private ConstructorInfo _ctor; private readonly Type _pluggedType; public Constructor(Type pluggedType) @@ -120,5 +121,19 @@ { return _ctor != null; } + + public void UseConstructor(Expression expression) + { + var finder = new ConstructorFinderVisitor(); + finder.Visit(expression); + + var ctor = finder.Constructor; + if (ctor == null) + { + throw new ApplicationException("Not a valid constructor function"); + } + + _ctor = ctor; + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/Graph/Plugin.cs =================================================================== --- trunk/Source/StructureMap/Graph/Plugin.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Graph/Plugin.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; using System.Reflection; using StructureMap.Pipeline; @@ -154,15 +155,14 @@ return templatedPlugin; } - public void SetFilledTypes(IList<Type> types) + public void UseConstructor(Expression expression) { - foreach (SetterProperty setter in _setters) - { - if (types.Contains(setter.Property.PropertyType)) - { - setter.IsMandatory = true; - } - } + _constructor.UseConstructor(expression); } + + public void UseSetterRule(Predicate<PropertyInfo> rule) + { + _setters.UseSetterRule(rule); + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/Graph/PluginCache.cs =================================================================== --- trunk/Source/StructureMap/Graph/PluginCache.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Graph/PluginCache.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using StructureMap.Emitting; using StructureMap.Util; @@ -9,16 +10,27 @@ public static class PluginCache { private static readonly Cache<Type, InstanceBuilder> _builders; - private static readonly List<Type> _filledTypes = new List<Type>(); private static readonly Cache<Type, Plugin> _plugins; + private static readonly List<Predicate<PropertyInfo>> _setterRules; static PluginCache() { - _plugins = new Cache<Type, Plugin>(t => new Plugin(t)); + _setterRules = new List<Predicate<PropertyInfo>>(); + _plugins = new Cache<Type, Plugin>(t => + { + var plugin = new Plugin(t); + foreach (var rule in _setterRules) + { + plugin.UseSetterRule(rule); + } + + return plugin; + }); + + _builders = new Cache<Type, InstanceBuilder>(t => { Plugin plugin = _plugins[t]; - plugin.SetFilledTypes(_filledTypes); return new InstanceBuilderAssembly(new[] {plugin}).Compile()[0]; }); } @@ -45,11 +57,6 @@ private static void createAndStoreBuilders(IEnumerable<Plugin> plugins) { - foreach (Plugin plugin in plugins) - { - plugin.SetFilledTypes(_filledTypes); - } - var assembly = new InstanceBuilderAssembly(plugins); assembly.Compile().ForEach(b => _builders[b.PluggedType] = b); } @@ -68,6 +75,7 @@ { lock (typeof (PluginCache)) { + _setterRules.Clear(); _builders.Clear(); _plugins.Clear(); } @@ -75,7 +83,14 @@ public static void AddFilledType(Type type) { - _filledTypes.Add(type); + Predicate<PropertyInfo> predicate = prop => prop.PropertyType == type; + UseSetterRule(predicate); } + + public static void UseSetterRule(Predicate<PropertyInfo> predicate) + { + _setterRules.Add(predicate); + _plugins.Each(plugin => plugin.UseSetterRule(predicate)); + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/Graph/PluginFamily.cs =================================================================== --- trunk/Source/StructureMap/Graph/PluginFamily.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Graph/PluginFamily.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -371,6 +371,8 @@ set { _defaultKey = value ?? string.Empty; } } + public Instance MissingInstance { get; set; } + #endregion } } \ No newline at end of file Modified: trunk/Source/StructureMap/Graph/SetterPropertyCollection.cs =================================================================== --- trunk/Source/StructureMap/Graph/SetterPropertyCollection.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Graph/SetterPropertyCollection.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -125,5 +125,10 @@ return null; } + + public void UseSetterRule(Predicate<PropertyInfo> rule) + { + _properties.FindAll(setter => rule(setter.Property)).ForEach(setter => setter.IsMandatory = true); + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/IContainer.cs =================================================================== --- trunk/Source/StructureMap/IContainer.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/IContainer.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -57,7 +57,6 @@ /// <summary> /// Creates a new instance of the requested type T using the supplied Instance. Mostly used internally /// </summary> - /// <param name="pluginType"></param> /// <param name="instance"></param> /// <returns></returns> T GetInstance<T>(Instance instance); @@ -81,7 +80,6 @@ /// </summary> /// <param name="pluginType"></param> /// <param name="instanceKey"></param> - /// <param name="instance"></param> /// <returns></returns> object TryGetInstance(Type pluginType, string instanceKey); @@ -89,7 +87,6 @@ /// Creates or finds the default instance of the pluginType. Returns null if the pluginType is not known to the container. /// </summary> /// <param name="pluginType"></param> - /// <param name="instance"></param> /// <returns></returns> object TryGetInstance(Type pluginType); @@ -97,7 +94,6 @@ /// Creates or finds the default instance of type T. Returns the default value of T if it is not known to the container. /// </summary> /// <typeparam name="T"></typeparam> - /// <param name="instance"></param> /// <returns></returns> T TryGetInstance<T>(); @@ -105,7 +101,6 @@ /// Creates or finds the named instance of type T. Returns the default value of T if the named instance is not known to the container. /// </summary> /// <typeparam name="T"></typeparam> - /// <param name="instance"></param> /// <returns></returns> T TryGetInstance<T>(string instanceKey); @@ -183,11 +178,9 @@ /// <summary> /// Gets the default instance of type T using the explicitly configured arguments from the "args" /// </summary> - /// <typeparam name="T"></typeparam> + /// <param name="type"></param> /// <param name="args"></param> /// <returns></returns> - - IList GetAllInstances(Type type, ExplicitArguments args); T GetInstance<T>(ExplicitArguments args); @@ -222,5 +215,15 @@ /// </summary> /// <typeparam name="T"></typeparam> void EjectAllInstancesOf<T>(); + + /// <summary> + /// The "BuildUp" method takes in an already constructed object + /// and uses Setter Injection to push in configured dependencies + /// of that object + /// </summary> + /// <param name="target"></param> + void BuildUp(object target); + + void SetDefault(Type pluginType, Instance instance); } } \ No newline at end of file Modified: trunk/Source/StructureMap/IInstanceFactory.cs =================================================================== --- trunk/Source/StructureMap/IInstanceFactory.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/IInstanceFactory.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -14,6 +14,7 @@ Type PluginType { get; } IEnumerable<IInstance> Instances { get; } IBuildPolicy Policy { get; } + Instance MissingInstance { get; set; } void AddInstance(Instance instance); Instance AddType<T>(); Modified: trunk/Source/StructureMap/InitializationExpression.cs =================================================================== --- trunk/Source/StructureMap/InitializationExpression.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/InitializationExpression.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -166,6 +166,14 @@ /// <typeparam name="PLUGINTYPE"></typeparam> /// <returns></returns> CreatePluginFamilyExpression<PLUGINTYPE> FillAllPropertiesOfType<PLUGINTYPE>(); + + /// <summary> + /// Creates automatic "policies" for which public setters are considered mandatory + /// properties by StructureMap that will be "setter injected" as part of the + /// construction process. + /// </summary> + /// <param name="action"></param> + void SetAllProperties(Action<SetterConvention> action); } public class InitializationExpression : ConfigurationExpression, IInitializationExpression @@ -178,7 +186,14 @@ public bool UseDefaultStructureMapConfigFile { - set { _parserBuilder.UseAndEnforceExistenceOfDefaultFile = value; } + set + { + _parserBuilder.UseAndEnforceExistenceOfDefaultFile = value; + if (!value) + { + _parserBuilder.IgnoreDefaultFile = true; + } + } } public bool IgnoreStructureMapConfig Modified: trunk/Source/StructureMap/InstanceBuilder.cs =================================================================== --- trunk/Source/StructureMap/InstanceBuilder.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/InstanceBuilder.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -11,10 +11,13 @@ { private Container _manager; + // DO NOT ELIMINATE THIS METHOD public InstanceBuilder(){} public abstract Type PluggedType { get; } public abstract object BuildInstance(IConfiguredInstance instance, BuildSession session); + + public virtual void BuildUp(IConfiguredInstance instance, BuildSession session, object target) { } } } \ No newline at end of file Modified: trunk/Source/StructureMap/InstanceFactory.cs =================================================================== --- trunk/Source/StructureMap/InstanceFactory.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/InstanceFactory.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -17,6 +17,7 @@ private readonly Type _pluginType; private IBuildPolicy _policy = new BuildPolicy(); + #region constructor functions @@ -40,8 +41,8 @@ _policy = family.Policy; _pluginType = family.PluginType; + MissingInstance = family.MissingInstance; - family.EachInstance(AddInstance); } catch (StructureMapException) @@ -74,6 +75,8 @@ #region IInstanceFactory Members + public Instance MissingInstance { get; set; } + public Type PluginType { get { return _pluginType; } @@ -132,7 +135,7 @@ public Instance FindInstance(string name) { - return _instances[name]; + return _instances[name] ?? MissingInstance; } public void ImportFrom(PluginFamily family) Modified: trunk/Source/StructureMap/ObjectFactory.cs =================================================================== --- trunk/Source/StructureMap/ObjectFactory.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/ObjectFactory.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -417,5 +417,16 @@ return container.TryGetInstance<T>(instanceKey); } + /// <summary> + /// The "BuildUp" method takes in an already constructed object + /// and uses Setter Injection to push in configured dependencies + /// of that object + /// </summary> + /// <param name="target"></param> + public static void BuildUp(object target) + { + container.BuildUp(target); + } + } } \ No newline at end of file Modified: trunk/Source/StructureMap/Pipeline/BuildFrame.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/BuildFrame.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/Pipeline/BuildFrame.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -2,12 +2,31 @@ namespace StructureMap.Pipeline { + public interface IBuildFrame + { + /// <summary> + /// The requested PluginType of the Instance being create + /// </summary> + Type RequestedType { get; } + + /// <summary> + /// The Name of the Instance being created + /// </summary> + string Name { get; } + + /// <summary> + /// The actual ConcreteType being created. This will not always + /// be available + /// </summary> + Type ConcreteType { get; } + } + /// <summary> /// Models the current place in an object graph during the construction of /// an instance. Provides contextual information that can be used /// to alter the desired construction of child objects /// </summary> - public class BuildFrame + public class BuildFrame : IBuildFrame { private readonly Type _concreteType; private readonly string _name; Added: trunk/Source/StructureMap/Pipeline/ConditionalInstance.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/ConditionalInstance.cs (rev 0) +++ trunk/Source/StructureMap/Pipeline/ConditionalInstance.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using StructureMap.Configuration.DSL.Expressions; + +namespace StructureMap.Pipeline +{ + public class ConditionalInstance<T> : ExpressedInstance<ConditionalInstance<T>> + { + // Conditional Instance keeps track of zero or more internal Instance + // objects against a Predicate<IContext> condition + private readonly List<InstanceCase> _cases = new List<InstanceCase>(); + + // The "default" Instance to use if none of the conditional predicates + // are met. If this is not explicitly defined, the ConditionalInstance + // will simply look for the default Instance of the desired + // PluginType + public Instance _default = new DefaultInstance(); + + + public ConditionalInstance(Action<ConditionalInstanceExpression<T>> action) + { + action(new ConditionalInstanceExpression<T>(this)); + } + + protected override string getDescription() + { + return "Conditional Instance of " + typeof (T).FullName; + } + + protected override object build(Type pluginType, BuildSession session) + { + // Find the first InstanceCase that matches the BuildSession/IContext + var instanceCase = _cases.Find(c => c.Predicate(session)); + + // Use the Instance from the InstanceCase if it exists, + // otherwise, use the "default" + var instance = instanceCase == null ? _default : instanceCase.Instance; + + // delegate to the chosen Instance + return instance.Build(pluginType, session); + } + + public class ConditionalInstanceExpression<T> + { + private readonly ConditionalInstance<T> _parent; + + public ConditionalInstanceExpression(ConditionalInstance<T> parent) + { + _parent = parent; + } + + public ThenItExpression<T> If(Predicate<IContext> predicate) + { + return new InstanceExpression<T>(i => + { + var theCase = new InstanceCase() {Instance = i, Predicate = predicate}; + _parent._cases.Add(theCase); + }); + } + + public IsExpression<T> TheDefault + { + get + { + return new InstanceExpression<T>(i => _parent._default = i); + } + } + + + } + + protected override ConditionalInstance<T> thisInstance + { + get { return this; } + } + } + + public class InstanceCase + { + public Predicate<IContext> Predicate { get; set; } + public Instance Instance { get; set; } + } +} \ No newline at end of file Modified: trunk/Source/StructureMap/ReflectionHelper.cs =================================================================== --- trunk/Source/StructureMap/ReflectionHelper.cs 2009-01-02 23:58:17 UTC (rev 213) +++ trunk/Source/StructureMap/ReflectionHelper.cs 2009-01-03 00:07:32 UTC (rev 214) @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq.Expressions; using System.Reflection; @@ -58,4 +61,407 @@ return methodCall.Method; } } + + /// <summary> + /// Provides virtual methods that can be used by subclasses to parse an expression tree. + /// </summary> + /// <remarks> + /// This class actually already exists in the System.Core assembly...as an internal class. + /// I can only speculate as to why it is internal, but it is obviously much too dangerous + /// for anyone outside of Microsoft to be using... + /// </remarks> + [DebuggerStepThrough, DebuggerNonUserCode] + public abstract class ExpressionVisitorBase + { + public virtual Expression Visit(Expression exp) + { + if (exp == null) return exp; + + switch (exp.NodeType) + { + case ExpressionType.Negate: + case ExpressionType.NegateChecked: + case ExpressionType.Not: + case ExpressionType.Convert: + case ExpressionType.ConvertChecked: + case ExpressionType.ArrayLength: + case ExpressionType.Quote: + case ExpressionType.TypeAs: + return VisitUnary((UnaryExpression)exp); + case ExpressionType.Add: + case ExpressionType.AddChecked: + case ExpressionType.Subtract: + case ExpressionType.SubtractChecked: + case ExpressionType.Multiply: + case ExpressionType.MultiplyChecked: + case ExpressionType.Divide: + case ExpressionType.Modulo: + case ExpressionType.And: + case ExpressionType.AndAlso: + case ExpressionType.Or: + case ExpressionType.OrElse: + case ExpressionType.LessThan: + case ExpressionType.LessThanOrEqual: + case ExpressionType.GreaterThan: + case ExpressionType.GreaterThanOrEqual: + case ExpressionType.Equal: + case ExpressionType.NotEqual: + case ExpressionType.Coalesce: + case ExpressionType.ArrayIndex: + case ExpressionType.RightShift: + case ExpressionType.LeftShift: + case ExpressionType.ExclusiveOr: + return VisitBinary((BinaryExpression)exp); + case ExpressionType.TypeIs: + return VisitTypeIs((TypeBinaryExpression)exp); + case ExpressionType.Conditional: + return VisitConditional((ConditionalExpression)exp); + case ExpressionType.Constant: + return VisitConstant((ConstantExpression)exp); + case ExpressionType.Parameter: + return VisitParameter((ParameterExpression)exp); + case ExpressionType.MemberAccess: + return VisitMemberAccess((MemberExpression)exp); + case ExpressionType.Call: + return VisitMethodCall((MethodCallExpression)exp); + case ExpressionType.Lambda: + return VisitLambda((LambdaExpression)exp); + case ExpressionType.New: + return VisitNew((NewExpression)exp); + case ExpressionType.NewArrayInit: + case ExpressionType.NewArrayBounds: + return VisitNewArray((NewArrayExpression)exp); + case ExpressionType.Invoke: + return VisitInvocation((InvocationExpression)exp); + case ExpressionType.MemberInit: + return VisitMemberInit((MemberInitExpression)exp); + case ExpressionType.ListInit: + return VisitListInit((ListInitExpression)exp); + default: + throw new NotSupportedException(String.Format("Unhandled expression type: '{0}'", exp.NodeType)); + } + } + + protected virtual MemberBinding VisitBinding(MemberBinding binding) + { + switch (binding.BindingType) + { + case MemberBindingType.Assignment: + return VisitMemberAssignment((MemberAssignment)binding); + case MemberBindingType.MemberBinding: + return VisitMemberMemberBinding((MemberMemberBinding)binding); + case MemberBindingType.ListBinding: + return VisitMemberListBinding((MemberListBinding)binding); + default: + throw new NotSupportedException(string.Format("Unhandled binding type '{0}'", binding.BindingType)); + } + } + + protected virtual ElementInit VisitElementInitializer(ElementInit initializer) + { + ReadOnlyCollection<Expression> arguments = VisitList(initializer.Arguments); + if (arguments != initializer.Arguments) + { + return Expression.ElementInit(initializer.AddMethod, arguments); + } + return initializer; + } + + protected virtual Expression VisitUnary(UnaryExpression u) + { + Expression operand = Visit(u.Operand); + if (operand != u.Operand) + { + return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method); + } + return u; + } + + protected virtual Expression VisitBinary(BinaryExpression b) + { + Expression left = Visit(b.Left); + Expression right = Visit(b.Right); + Expression conversion = Visit(b.Conversion); + + if (left != b.Left || right != b.Right || conversion != b.Conversion) + { + if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) + return Expression.Coalesce(left, right, conversion as LambdaExpression); + else + return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); + } + return b; + } + + protected virtual Expression VisitTypeIs(TypeBinaryExpression b) + { + Expression expr = Visit(b.Expression); + if (expr != b.Expression) + { + return Expression.TypeIs(expr, b.TypeOperand); + } + return b; + } + + protected virtual Expression VisitConstant(ConstantExpression c) + { + return c; + } + + protected virtual Expression VisitConditional(ConditionalExpression c) + { + Expression test = Visit(c.Test); + Expression ifTrue = Visit(c.IfTrue); + Expression ifFalse = Visit(c.IfFalse); + + if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse) + { + return Expression.Condition(test, ifTrue, ifFalse); + } + + return c; + } + + protected virtual Expression VisitParameter(ParameterExpression p) + { + return p; + } + + protected virtual Expression VisitMemberAccess(MemberExpression m) + { + Expression exp = Visit(m.Expression); + if (exp != m.Expression) + { + return Expression.MakeMemberAccess(exp, m.Member); + } + return m; + } + + protected virtual Expression VisitMethodCall(MethodCallExpression m) + { + Expression obj = Visit(m.Object); + IEnumerable<Expression> args = VisitList(m.Arguments); + + if (obj != m.Object || args != m.Arguments) + { + return Expression.Call(obj, m.Method, args); + } + + return m; + } + + protected virtual ReadOnlyCollection<Expression> VisitList(ReadOnlyCollection<Expression> original) + { + List<Expression> list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + Expression p = Visit(original[i]); + if (list != null) + { + list.Add(p); + } + else if (p != original[i]) + { + list = new List<Expression>(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(p); + } + } + + if (list != null) + return list.AsReadOnly(); + + return original; + } + + protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment) + { + Expression e = Visit(assignment.Expression); + + if (e != assignment.Expression) + { + return Expression.Bind(assignment.Member, e); + } + + return assignment; + } + + protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) + { + IEnumerable<MemberBinding> bindings = VisitBindingList(binding.Bindings); + + if (bindings != binding.Bindings) + { + return Expression.MemberBind(binding.Member, bindings); + } + + return binding; + } + + protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) + { + IEnumerable<ElementInit> initializers = VisitElementInitializerList(binding.Initializers); + + if (initializers != binding.Initializers) + { + return Expression.ListBind(binding.Member, initializers); + } + return binding; + } + + protected virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original) + { + List<MemberBinding> list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + MemberBinding b = VisitBinding(original[i]); + if (list != null) + { + list.Add(b); + } + else if (b != original[i]) + { + list = new List<MemberBinding>(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(b); + } + } + + if (list != null) + return list; + + return original; + } + + protected virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original) + { + List<ElementInit> list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + ElementInit init = VisitElementInitializer(original[i]); + if (list != null) + { + list.Add(init); + } + else if (init != original[i]) + { + list = new List<ElementInit>(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(init); + } + } + + if (list != null) + return list; + + return original; + } + + protected virtual Expression VisitLambda(LambdaExpression lambda) + { + Expression body = Visit(lambda.Body); + if (body != lambda.Body) + { + return Expression.Lambda(lambda.Type, body, lambda.Parameters); + } + return lambda; + } + + protected virtual N... [truncated message content] |