|
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] |