Repository: ekonbenefits/dynamitey Branch: master Commit: c44f5c57cb8a Files: 73 Total size: 705.5 KB Directory structure: gitextract_b38rdefz/ ├── .appveyor.yml ├── .github/ │ └── workflows/ │ ├── dotnet.yml │ └── dotnet48.yml ├── .gitignore ├── .vscode/ │ └── tasks.json ├── Directory.Build.props ├── Dynamitey/ │ ├── Builder.cs │ ├── CacheableInvocation.cs │ ├── Dynamic.cs │ ├── DynamicObjects/ │ │ ├── BaseDictionary.cs │ │ ├── BaseForwarder.cs │ │ ├── BaseObject.cs │ │ ├── Builder.cs │ │ ├── Dictionary.cs │ │ ├── Dummy.cs │ │ ├── ExtensionToInstanceProxy.cs │ │ ├── Factory.cs │ │ ├── FauxType.cs │ │ ├── FluentStringLookup.cs │ │ ├── Get.cs │ │ ├── LateType.cs │ │ ├── Lazy.cs │ │ ├── LinqInstanceProxy.cs │ │ ├── List.cs │ │ ├── Mimic.cs │ │ ├── Recorder.cs │ │ └── RegexMatch.cs │ ├── Dynamitey.csproj │ ├── Expando.cs │ ├── FluentRegex.cs │ ├── InlineLambdas.cs │ ├── InlineLambdas.tt │ ├── Internal/ │ │ ├── Compat/ │ │ │ └── Net40.cs │ │ ├── Curry.cs │ │ ├── InvokeSetters.cs │ │ └── Optimization/ │ │ ├── BareBonesList.cs │ │ ├── BinderHash.cs │ │ ├── InvokeHelper-Regular.cs │ │ ├── InvokeHelper.cs │ │ ├── InvokeHelper.tt │ │ └── Util.cs │ ├── Invocation.cs │ ├── InvokeArg.cs │ ├── InvokeContext.cs │ ├── InvokeMemberName.cs │ ├── PartialApply.cs │ ├── ThisFunctions.cs │ ├── ThisFunctions.tt │ ├── Tupler.cs │ └── sn.snk ├── Dynamitey.sln ├── Dynamitey.sln.DotSettings ├── License.txt ├── NuGet.config ├── Readme.md ├── SupportLibrary/ │ ├── SupportLibrary.csproj │ └── SupportTypes.cs ├── TestResult.xml ├── Tests/ │ ├── Curry.cs │ ├── DynamicObjects.cs │ ├── ExpandoObjs.cs │ ├── Helper.cs │ ├── Impromptu.cs │ ├── Invoke.cs │ ├── Linq.cs │ ├── MimicTest.cs │ ├── PrivateTest.cs │ ├── SpeedTest.cs │ ├── Tests.csproj │ ├── TimeIt.cs │ └── TuplerTest.cs ├── Version.props └── build.fsx ================================================ FILE CONTENTS ================================================ ================================================ FILE: .appveyor.yml ================================================ image: Visual Studio 2017 configuration: Debug build: off install: - ps: nuget install FSharp.Compiler.Tools -ExcludeVersion -OutputDirectory extra build_script: - cmd: set PATH=%PATH%;%APPVEYOR_BUILD_FOLDER%\extra\FSharp.Compiler.Tools\tools\ - cmd: fsi --exec ./build.fsx test: off artifacts: - path: '**\bin\*\*.nupkg' skip_branch_with_pr: true skip_tags: true deploy: - provider: NuGet server: https://www.myget.org/F/dynamitey-ci/api/v2/package api_key: secure: yKbBrG0QiTfXUvND1/cMMNHxH1Bgal5g7c0pWGwqvjCtKGTtWkpvE2KlZb6E2ZgB skip_symbols: false symbol_server: https://www.myget.org/F/dynamitey-ci/symbols/api/v2/package for: - branches: except: - /v.*/ environment: vsuffix: alpha$(APPVEYOR_BUILD_NUMBER) is_prerelease: true - branches: only: - /v.*-beta/ environment: vsuffix: beta$(APPVEYOR_BUILD_NUMBER) is_prerelease: true - branches: only: - /v[\d,.]*/ configuration: Release environment: vsuffix: $(APPVEYOR_BUILD_NUMBER) is_prerelease: false ================================================ FILE: .github/workflows/dotnet.yml ================================================ name: Build .net core on: [push] jobs: build: name: Test ${{ matrix.os }} for dotnet ${{ matrix.dotnet }} runs-on: ${{ matrix.os }} strategy: matrix: dotnet: [ '8.0.x' ] os: [ubuntu-latest, macOS-latest] steps: - uses: actions/checkout@v4 - name: Setup .NET Core uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet }} - name: Build with dotnet core run: dotnet build --configuration Release - name: Tests run: dotnet test Tests/Tests.csproj --configuration Release --no-build --no-restore --filter=TestCategory!=Performance ================================================ FILE: .github/workflows/dotnet48.yml ================================================ name: Build CrossComple .net core/.net framework Windows on: [push] jobs: build: name: Test Windows .net Framework and Core runs-on: windows-2022 steps: - uses: actions/checkout@v4 - uses: NuGet/setup-nuget@v2 - uses: microsoft/setup-msbuild@v2 with: dotnet-version: 4.8 - name: Restore Packages run: nuget restore Dynamitey.sln - name: Build solution run: msbuild Dynamitey.sln -t:rebuild -property:Configuration=Release - name: Test uses: josepho0918/vstest-action@0e887de8dcfab5ce3eecaf4ad6320bb9b3ecf633 with: testAssembly: Tests.dll searchFolder: .\Tests\bin\Release\*\ runInParallel: true otherConsoleOptions: /TestCaseFilter:"(TestCategory!=Performance)" platform: x64 - name: Publish run: dotnet nuget push '${{ github.workspace }}\publish\*.nupkg' --source https://nuget.pkg.github.com/ekonbenefits/index.json --api-key ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. f # User-specific files *.suo *.user *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ build/ [Bb]in/ [Oo]bj/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.log *.scc # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch *.ncrunch* .*crunch*.local.xml # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.Publish.xml *.pubxml # NuGet Packages Directory ## TODO: If you have NuGet Package Restore enabled, uncomment the next line packages/ # Windows Azure Build Output csx *.build.csdef # Windows Store app package directory AppPackages/ # Others sql/ *.Cache ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.[Pp]ublish.xml *.pfx *.publishsettings # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files App_Data/*.mdf App_Data/*.ldf # ========================= # Windows detritus # ========================= # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Mac crap .DS_Store /dist/*.nupkg *.userprefs .fake/* .nuget/NuGet.exe .idea/* .vs/* .ionide/* ================================================ FILE: .vscode/tasks.json ================================================ { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "0.1.0", "command": "./build.fsx", "args": ["Test"], "windows":{ "command": "C:\\Program Files (x86)\\Microsoft SDKs\\F#\\4.1\\Framework\\v4.0\\fsi", "args": ["--exec", "./build.fsx", "Test"] }, "isShellCommand": true, "showOutput": "always", "problemMatcher":"$msCompile" } ================================================ FILE: Directory.Build.props ================================================ True ================================================ FILE: Dynamitey/Builder.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Linq; using Dynamitey.DynamicObjects; namespace Dynamitey { /// /// Builds Objects with a Fluent Syntax /// public static class Builder { /// /// New Builder /// /// public static IBuilder New() { return new Builder(); } /// /// New Builder /// /// The type of the object prototype. /// public static IBuilder New() where TObjectPrototype : new() { return new Builder(); } } /// /// Syntax for a quick new inline prototype object /// public static class Build { private static readonly dynamic _objectBuilder = new Builder().Object; private static readonly dynamic _listBuilder = Dynamic.Curry(new Builder().ListSetup()). List(); /// /// Gets the new object builder. /// /// The new object. public static dynamic NewObject => _objectBuilder; /// /// Gets the new list builder. /// /// The new list. public static dynamic NewList => _listBuilder; } /// /// Syntax for a quick inline object property setup /// /// The type of the object prototype. public static class Build where TObjectPrototype : new() { // ReSharper disable StaticFieldInGenericType private static readonly dynamic _typedBuilder = new Builder().Object; // ReSharper restore StaticFieldInGenericType // ReSharper disable StaticFieldInGenericType private static readonly dynamic _typedListBuilder = Dynamic.Curry(new Builder().ListSetup()).List(); // ReSharper restore StaticFieldInGenericType /// /// Gets the new object builder. /// /// The new. public static dynamic NewObject => _typedBuilder; /// /// Gets the new list builder. /// /// The new list. public static dynamic NewList => _typedListBuilder; } /// /// Encapsulates an Activator /// public class Activate { /// /// Initializes a new instance of the class. /// /// The type. /// The args. public Activate(Type type, params object[] args) { Type = type; var tArg = args.OfType>().SingleOrDefault(); if (tArg != null) Arguments = tArg; else Arguments = () => args; } /// /// Initializes a new instance of the class. With Factory Function /// /// The type. /// The args. public Activate(Type type, Func args) { Type = type; Arguments = args; } /// /// Gets or sets the constructor type. /// /// The type. public virtual Type Type { get; private set; } /// /// Gets or sets the constructor arguments. /// /// The arguments. public virtual Func Arguments { get; private set; } /// /// Creates this instance. /// /// public virtual dynamic Create() { object[] tArgs = Arguments(); return Dynamic.InvokeConstructor(Type, tArgs); } } /// /// Encapsulates an Activator /// /// The type of the object prototype. public class Activate : Activate { /// /// Initializes a new instance of the class. /// /// The args. public Activate(params object[] args) : base(typeof(TObjectPrototype), args) { } /// /// Initializes a new instance of the class. With Factory Function /// /// The args. public Activate(Func args) : base(typeof(TObjectPrototype), args) { } /// /// Creates this instance. /// /// public override dynamic Create() { var tArgs = Arguments(); if(tArgs.Any()) return base.Create(); TObjectPrototype tObjectPrototype; try { tObjectPrototype = Activator.CreateInstance();//Try first because it's really fast, but won't work with optional parameters } catch (Exception) { tObjectPrototype = Dynamic.InvokeConstructor(typeof(TObjectPrototype)); } return tObjectPrototype; } } } ================================================ FILE: Dynamitey/CacheableInvocation.cs ================================================ using System; using System.Dynamic; using System.Linq; using System.Runtime.CompilerServices; using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; using System.Reflection; using Dynamitey.Internal.Compat; using System.Collections; using System.Collections.Generic; namespace Dynamitey { /// /// Cacheable representation of an invocation without the target or arguments also by default only does public methods to make it easier to cache. /// /// public class CacheableInvocation:Invocation { /// /// Creates the cacheable convert call. /// /// Type of the convert. /// if set to true [convert explicit]. /// public static CacheableInvocation CreateConvert(Type convertType, bool convertExplicit=false) { return new CacheableInvocation(InvocationKind.Convert, convertType: convertType, convertExplicit: convertExplicit); } /// /// Creates the cacheable method or indexer or property call. /// /// The kind. /// The name. /// The callInfo. /// The context. /// public static CacheableInvocation CreateCall(InvocationKind kind, String_OR_InvokeMemberName name = null, CallInfo callInfo = null,object context = null) { var tArgCount = callInfo?.ArgumentCount ?? 0; var tArgNames = callInfo?.ArgumentNames.ToArray(); return new CacheableInvocation(kind, name, tArgCount, tArgNames, context); } private readonly int _argCount; private readonly string[] _argNames; private readonly bool _staticContext; private readonly Type _context; //[NonSerialized] private CallSite _callSite; //[NonSerialized] private CallSite _callSite2; //[NonSerialized] private CallSite _callSite3; //[NonSerialized] private CallSite _callSite4; private readonly bool _convertExplicit; private readonly Type _convertType; /// /// Initializes a new instance of the class. /// /// The kind. /// The name. /// The arg count. /// The arg names. /// The context. /// Type of the convert. /// if set to true [convert explict]. /// The stored args. public CacheableInvocation(InvocationKind kind, String_OR_InvokeMemberName name=null, int argCount =0, string[] argNames =null, object context = null, Type convertType = null, bool convertExplicit = false, object[] storedArgs = null) : base(kind, name, storedArgs) { _convertType = convertType; _convertExplicit = convertExplicit; _argNames = argNames ?? new string[] {}; if (storedArgs != null) { _argCount = storedArgs.Length; Args = Util.GetArgsAndNames(storedArgs, out var tArgNames); if (_argNames.Length < tArgNames.Length) { _argNames = tArgNames; } } switch (kind) //Set required argcount values { case InvocationKind.GetIndex: if (argCount < 1) { throw new ArgumentException("Arg Count must be at least 1 for a GetIndex", nameof(argCount)); } _argCount = argCount; break; case InvocationKind.SetIndex: if (argCount < 2) { throw new ArgumentException("Arg Count Must be at least 2 for a SetIndex", nameof(argCount)); } _argCount = argCount; break; case InvocationKind.Convert: _argCount = 0; if(convertType==null) throw new ArgumentNullException(nameof(convertType)," Convert Requires Convert Type "); break; case InvocationKind.SubtractAssign: case InvocationKind.AddAssign: case InvocationKind.Set: _argCount = 1; break; case InvocationKind.Get: case InvocationKind.IsEvent: _argCount = 0; break; default: _argCount = Math.Max(argCount, _argNames.Length); break; } if (_argCount > 0)//setup argName array { var tBlank = new string[_argCount]; if (_argNames.Length != 0) Array.Copy(_argNames, 0, tBlank, tBlank.Length - _argNames.Length, _argNames.Length); else tBlank = null; _argNames = tBlank; } if (context != null) { var dummy = context.GetTargetContext(out _context, out _staticContext); //lgtm [cs/useless-assignment-to-local] } else { _context = typeof (object); } } /// /// Equalses the specified other. /// /// The other. /// public bool Equals(CacheableInvocation other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return base.Equals(other) && other._argCount == _argCount && (_argNames ?? new string[] { }).SequenceEqual(other._argNames ?? new string[] { }) && other._staticContext.Equals(_staticContext) && Equals(other._context, _context) && other._convertExplicit.Equals(_convertExplicit) && Equals(other._convertType, _convertType); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; return Equals(obj as CacheableInvocation); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { unchecked { int result = base.GetHashCode(); result = (result*397) ^ _argCount; result = (result*397) ^ (_argNames != null ? ((IStructuralEquatable)_argNames).GetHashCode(EqualityComparer.Default) : 0); result = (result*397) ^ _staticContext.GetHashCode(); result = (result*397) ^ (_context != null ? _context.GetHashCode() : 0); result = (result*397) ^ _convertExplicit.GetHashCode(); result = (result*397) ^ (_convertType != null ? _convertType.GetHashCode() : 0); return result; } } /// /// Invokes the invocation on specified target with specific args. /// /// The target. /// The args. /// /// CacheableInvocation can't change conversion type on invoke.;args /// Unknown Invocation Kind: public override object Invoke(object target, params object[] args) { if (target is InvokeContext tIContext) { target = tIContext.Target; } if (args == null) { args = new object[]{null}; } if (args.Length != _argCount) { switch (Kind) { case InvocationKind.Convert: if (args.Length > 0) { if (!Equals(args[0], _convertType)) throw new ArgumentException("CacheableInvocation can't change conversion type on invoke.", nameof(args)); } if (args.Length > 1) { if(!Equals(args[1], _convertExplicit)) throw new ArgumentException("CacheableInvocation can't change explicit/implicit conversion on invoke.", nameof(args)); } if(args.Length > 2) goto default; break; default: throw new ArgumentException("args", $"Incorrect number of Arguments for CachedInvocation, Expected:{_argCount}"); } } switch (Kind) { case InvocationKind.Constructor: var tTarget = (Type) target; return InvokeHelper.InvokeConstructorCallSite(tTarget, tTarget.GetTypeInfo().IsValueType, args, _argNames, ref _callSite); case InvocationKind.Convert: return InvokeHelper.InvokeConvertCallSite(target, _convertExplicit, _convertType, _context, ref _callSite); case InvocationKind.Get: return InvokeHelper.InvokeGetCallSite(target, Name.Name, _context, _staticContext, ref _callSite); case InvocationKind.Set: InvokeHelper.InvokeSetCallSite(target, Name.Name, args[0], _context, _staticContext, ref _callSite); return null; case InvocationKind.GetIndex: return InvokeHelper.InvokeGetIndexCallSite(target, args, _argNames, _context, _staticContext, ref _callSite); case InvocationKind.SetIndex: Dynamic.InvokeSetIndex(target, args); return null; case InvocationKind.InvokeMember: return InvokeHelper.InvokeMemberCallSite(target, (InvokeMemberName) Name, args, _argNames, _context, _staticContext, ref _callSite); case InvocationKind.InvokeMemberAction: InvokeHelper.InvokeMemberActionCallSite(target, (InvokeMemberName)Name, args, _argNames, _context, _staticContext, ref _callSite); return null; case InvocationKind.InvokeMemberUnknown: { try { var tObj = InvokeHelper.InvokeMemberCallSite(target, (InvokeMemberName)Name, args, _argNames, _context, _staticContext, ref _callSite); return tObj; } catch (RuntimeBinderException) { InvokeHelper.InvokeMemberActionCallSite(target, (InvokeMemberName)Name, args, _argNames, _context, _staticContext, ref _callSite2); return null; } } case InvocationKind.Invoke: return InvokeHelper.InvokeDirectCallSite(target, args, _argNames, _context, _staticContext, ref _callSite); case InvocationKind.InvokeAction: InvokeHelper.InvokeDirectActionCallSite(target, args, _argNames, _context, _staticContext, ref _callSite); return null; case InvocationKind.InvokeUnknown: { try { var tObj = InvokeHelper.InvokeDirectCallSite(target, args, _argNames, _context, _staticContext, ref _callSite); return tObj; } catch (RuntimeBinderException) { InvokeHelper.InvokeDirectActionCallSite(target, args, _argNames, _context, _staticContext, ref _callSite2); return null; } } case InvocationKind.AddAssign: InvokeHelper.InvokeAddAssignCallSite(target, Name.Name, args, _argNames, _context, _staticContext,ref _callSite,ref _callSite2,ref _callSite3, ref _callSite4); return null; case InvocationKind.SubtractAssign: InvokeHelper.InvokeSubtractAssignCallSite(target, Name.Name, args, _argNames, _context, _staticContext, ref _callSite, ref _callSite2, ref _callSite3, ref _callSite4); return null; case InvocationKind.IsEvent: return InvokeHelper.InvokeIsEventCallSite(target, Name.Name, _context, ref _callSite); default: throw new InvalidOperationException("Unknown Invocation Kind: " + Kind); } } } } ================================================ FILE: Dynamitey/Dynamic.cs ================================================ // // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using Dynamitey.Internal; using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; using System.Text.RegularExpressions; using Dynamitey.Internal.Compat; namespace Dynamitey { using System; /// /// Main API /// public static class Dynamic { /// /// Clears the dynamic binding caches. /// public static void ClearCaches() { InvokeHelper.ClearAllCaches(); } private static readonly dynamic ComBinder = new DynamicObjects.LateType("System.Dynamic.ComBinder, System.Dynamic, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); // ReSharper disable once MemberCanBePrivate.Global internal static readonly dynamic Impromptu = new DynamicObjects.LateType("ImpromptuInterface.Impromptu, ImpromptuInterface, PublicKeyToken=0b1781c923b2975b"); // ReSharper disable once MemberCanBePrivate.Global internal static readonly dynamic TypeDescriptor = new DynamicObjects.LateType("System.ComponentModel.TypeDescriptor, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); private static readonly Type ComObjectType; // ReSharper disable once MemberCanBePrivate.Global internal static readonly Type TypeConverterAttributeSL; static Dynamic() { try { ComObjectType = typeof(object).GetTypeInfo().Assembly.GetType("System.__ComObject"); } catch { ComObjectType = null; } try { TypeConverterAttributeSL = Type.GetType("System.ComponentModel.TypeConverter, System, Version=5.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", false); } catch { TypeConverterAttributeSL = null; } } /// /// Creates a cached call site at runtime. /// /// Type of the delegate. /// The CallSite binder. /// Member Name /// Permissions Context type /// The arg names. /// if set to true [static context]. /// if set to true [is event]. /// The CallSite /// /// Advanced usage only for serious custom dynamic invocation. /// /// public static CallSite CreateCallSite(Type delegateType, CallSiteBinder binder, String_OR_InvokeMemberName name, Type context, string[] argNames = null, bool staticContext = false, bool isEvent = false) => InvokeHelper.CreateCallSite(delegateType, binder.GetType(), InvokeHelper.Unknown, () => binder, (InvokeMemberName)name, context, argNames, staticContext, isEvent); /// /// Creates the call site. /// /// /// The binder. /// The name. /// The context. /// The arg names. /// if set to true [static context]. /// if set to true [is event]. /// /// /// /// /// Unit test that exhibits usage /// (tBinder); /// tSite.Target.Invoke(tSite, tPoco, out tResult); /// Assert.AreEqual("success", tResult); /// ]]> /// /// public static CallSite CreateCallSite(CallSiteBinder binder, String_OR_InvokeMemberName name, Type context, string[] argNames = null, bool staticContext = false, bool isEvent = false) where T : class => InvokeHelper.CreateCallSite(binder.GetType(), InvokeHelper.Unknown, () => binder, (InvokeMemberName) name, context, argNames, staticContext, isEvent); /// /// Puts a dynamic linq proxy around the specified enumerable. /// /// The enumerable. /// public static dynamic Linq(object enumerable) { if (enumerable .GetType() .GetTypeInfo() .GetInterfaces() .Where(it => it.GetTypeInfo().IsGenericType) .Any(it => it.GetGenericTypeDefinition() == typeof(IEnumerable<>))) { return new DynamicObjects.LinqInstanceProxy(enumerable); } if (enumerable is IEnumerable tempEnumerable) { enumerable = tempEnumerable.Cast(); } return new DynamicObjects.LinqInstanceProxy(enumerable); } /// /// Dynamically Invokes a member method using the DLR /// /// The target. /// The name. Can be a string it will be implicitly converted /// The args. /// The result /// /// Unit test that exhibits usage: /// /// (it => it.ToString()); /// /// var tValue = 1; /// var tOut = Impromptu.InvokeMember(tExpando, "Func", tValue); /// /// Assert.AreEqual(tValue.ToString(), tOut); /// ]]> /// /// public static dynamic InvokeMember(object target, String_OR_InvokeMemberName name, params object[] args) { target = target.GetTargetContext(out var context, out var staticContext); args = Util.GetArgsAndNames(args, out var argNames); CallSite callSite = null; return InvokeHelper.InvokeMemberCallSite(target, (InvokeMemberName)name, args, argNames, context, staticContext, ref callSite); } /// /// Invokes the binary operator. /// /// The left arg. /// The op. /// The right Arg. /// public static dynamic InvokeBinaryOperator(dynamic leftArg, ExpressionType op, dynamic rightArg) { switch (op) { case ExpressionType.Add: return leftArg + rightArg; case ExpressionType.AddAssign: leftArg += rightArg; return leftArg; case ExpressionType.AndAssign: leftArg &= rightArg; return leftArg; case ExpressionType.Divide: return leftArg/rightArg; case ExpressionType.DivideAssign: leftArg /= rightArg; return leftArg; case ExpressionType.Equal: return leftArg == rightArg; case ExpressionType.ExclusiveOr: return leftArg ^ rightArg; case ExpressionType.ExclusiveOrAssign: leftArg ^= rightArg; return leftArg; case ExpressionType.GreaterThan: return leftArg > rightArg; case ExpressionType.GreaterThanOrEqual: return leftArg >= rightArg; case ExpressionType.LeftShift: return leftArg << rightArg; case ExpressionType.LeftShiftAssign: leftArg <<= rightArg; return leftArg; case ExpressionType.LessThan: return leftArg < rightArg; case ExpressionType.LessThanOrEqual: return leftArg <= rightArg; case ExpressionType.Modulo: return leftArg%rightArg; case ExpressionType.ModuloAssign: leftArg %= rightArg; return leftArg; case ExpressionType.Multiply: return leftArg*rightArg; case ExpressionType.MultiplyAssign: leftArg *= rightArg; return leftArg; case ExpressionType.NotEqual: return leftArg != rightArg; case ExpressionType.OrAssign: leftArg |= rightArg; return leftArg; case ExpressionType.RightShift: return leftArg >> rightArg; case ExpressionType.RightShiftAssign: leftArg >>= rightArg; return leftArg; case ExpressionType.Subtract: return leftArg - rightArg; case ExpressionType.SubtractAssign: leftArg -= rightArg; return leftArg; case ExpressionType.Or: return leftArg | rightArg; case ExpressionType.And: return leftArg & rightArg; case ExpressionType.OrElse: return leftArg || rightArg; case ExpressionType.AndAlso: return leftArg && rightArg; default: throw new ArgumentException("Unsupported Operator", nameof(op)); } } [Obsolete("Use `InvokeUnaryOperator` instead.")] // ReSharper disable once IdentifierTypo public static dynamic InvokeUnaryOpartor(ExpressionType op, dynamic arg) => InvokeUnaryOperator(op, (object)arg); /// /// Invokes the unary operator. /// /// The arg. /// The op. /// public static dynamic InvokeUnaryOperator(ExpressionType op, dynamic arg) { switch (op) { case ExpressionType.Not: return !arg; case ExpressionType.Negate: return -arg; case ExpressionType.Decrement: return --arg; case ExpressionType.Increment: return ++arg; default: throw new ArgumentException("Unsupported Operator", nameof(op)); } } /// /// Invokes the specified target using the DLR; /// /// The target. /// The args. /// public static dynamic Invoke(object target, params object[] args) { target = target.GetTargetContext(out var context, out var staticContext); args = Util.GetArgsAndNames(args, out var argNames); CallSite callSite = null; return InvokeHelper.InvokeDirectCallSite(target, args, argNames, context, staticContext, ref callSite); } /// /// Dynamically Invokes indexer using the DLR. /// /// The target. /// The indexes. /// public static dynamic InvokeGetIndex(object target, params object[] indexes) { target = target.GetTargetContext(out var tContext, out var tStaticContext); indexes = Util.GetArgsAndNames(indexes, out var tArgNames); CallSite tCallSite = null; return InvokeHelper.InvokeGetIndexCallSite(target, indexes, tArgNames, tContext, tStaticContext, ref tCallSite); } /// /// Convenience version of InvokeSetIndex that separates value and indexes. /// /// The target. /// The value /// The indexes /// public static object InvokeSetValueOnIndexes(object target, object value, params object[] indexes) { var tList = new List(indexes) {value}; return InvokeSetIndex(target, indexesThenValue: tList.ToArray()); } /// /// Invokes setindex. /// /// The target. /// The indexes then value. public static object InvokeSetIndex(object target, params object[] indexesThenValue) { if (indexesThenValue.Length < 2) { throw new ArgumentException("Requires at least one index and one value", nameof(indexesThenValue)); } target = target.GetTargetContext(out var tContext, out var tStaticContext); indexesThenValue = Util.GetArgsAndNames(indexesThenValue, out var tArgNames); CallSite tCallSite = null; return InvokeHelper.InvokeSetIndexCallSite(target, indexesThenValue, tArgNames, tContext, tStaticContext, ref tCallSite); } /// /// Dynamically Invokes a member method which returns void using the DLR /// /// The target. /// The name. /// The args. /// /// Unit test that exhibits usage: /// /// (it => tTest = it); /// /// Impromptu.InvokeMemberAction(tExpando, "Action", tValue); /// /// Assert.AreEqual(tValue, tTest); /// ]]> /// /// public static void InvokeMemberAction(object target, String_OR_InvokeMemberName name, params object[] args) { target = target.GetTargetContext(out var tContext, out var tStaticContext); args = Util.GetArgsAndNames(args, out var tArgNames); CallSite tCallSite = null; InvokeHelper.InvokeMemberActionCallSite(target, (InvokeMemberName)name, args, tArgNames, tContext, tStaticContext, ref tCallSite); } /// /// Invokes the action using the DLR /// /// The target. /// The args. public static void InvokeAction(object target, params object[] args) { target = target.GetTargetContext(out var tContext, out var tStaticContext); args = Util.GetArgsAndNames(args, out var tArgNames); CallSite tCallSite = null; InvokeHelper.InvokeDirectActionCallSite(target, args, tArgNames, tContext, tStaticContext, ref tCallSite); } /// /// Dynamically Invokes a set member using the DLR. /// /// The target. /// The name. /// The value. /// /// Unit test that exhibits usage: /// /// /// /// /// /// if you call a static property off a type with a static context the csharp dlr binder won't do it, so this method reverts to reflection /// public static object InvokeSet(object target, string name, object value) { target = target.GetTargetContext(out var tContext, out var tStaticContext); tContext = tContext.FixContext(); CallSite tCallSite = null; return InvokeHelper.InvokeSetCallSite(target, name, value, tContext, tStaticContext, ref tCallSite); } /// /// Invokes the set on the end of a property chain. /// /// The target. /// The property chain. /// The value. public static object InvokeSetChain(object target, string propertyChain, object value) { var tProperties = _chainRegex.FluentMatches(propertyChain).ToList(); var tGetProperties = tProperties.Take(tProperties.Count - 1); var tTarget = target; foreach (var tProperty in tGetProperties) { var tGetter = tProperty.Getter; var tIntIndexer = tProperty.IntIndexer; var tStringIndexer = tProperty.StringIndexer; if (tGetter != null) tTarget = InvokeGet(tTarget, tGetter); else if (tIntIndexer != null) tTarget = InvokeGetIndex(tTarget, Dynamic.CoerceConvert(tIntIndexer, typeof(int))); else if (tStringIndexer != null) tTarget = InvokeGetIndex(tTarget, tStringIndexer); else { throw new Exception($"Could Not Parse :'{propertyChain}'"); } } var tSetProperty = tProperties.Last(); var tSetGetter = tSetProperty.Getter; var tSetIntIndexer = tSetProperty.IntIndexer; var tSetStringIndexer = tSetProperty.StringIndexer; if (tSetGetter != null) return InvokeSet(tTarget, tSetGetter, value); if (tSetIntIndexer != null) return InvokeSetIndex(tTarget, Dynamic.CoerceConvert(tSetIntIndexer, typeof(int)), value); if (tSetStringIndexer != null) return InvokeSetIndex(tTarget, tSetStringIndexer, value); throw new Exception($"Could Not Parse :'{propertyChain}'"); } private static readonly dynamic _invokeSetAll = new InvokeSetters(); /// /// Call Like method invokes set on target and a list of property/value. Invoke with dictionary, anonymous type or named arguments. /// /// The invoke set all. public static dynamic InvokeSetAll => _invokeSetAll; /// /// Wraps a target to partial apply a method (or target if you can invoke target directly eg delegate). /// /// The target. /// The total arg count. /// public static dynamic Curry(object target, int? totalArgCount = null) { if (target is Delegate && !totalArgCount.HasValue) return Curry((Delegate) target); return new Curry(target, totalArgCount); } /// /// Wraps a delegate to partially apply it. /// /// The target. /// public static dynamic Curry(Delegate target) { return new Curry(target, target.GetMethodInfo().GetParameters().Length); } /// /// Dynamically Invokes a get member using the DLR. /// /// The target. /// The name. /// The result. /// /// Unit Test that describes usage /// /// /// /// public static dynamic InvokeGet(object target, string name) { target = target.GetTargetContext(out var tContext, out var tStaticContext); CallSite tSite = null; return InvokeHelper.InvokeGetCallSite(target, name, tContext, tStaticContext, ref tSite); } private static readonly Regex _chainRegex = new Regex(@"((\.?(?\w+))|(\[(?\d+)\])|(\['(?\w+)'\]))"); /// /// Invokes the getter property chain. /// /// The target. /// The property chain. /// public static dynamic InvokeGetChain(object target, string propertyChain) { var tProperties = _chainRegex.FluentMatches(propertyChain); var tTarget = target; foreach (var tProperty in tProperties) { var tGetter = tProperty.Getter; var tIntIndexer = tProperty.IntIndexer; var tStringIndexer = tProperty.StringIndexer; if (tGetter != null) tTarget = InvokeGet(tTarget, tGetter); else if (tIntIndexer != null) tTarget = InvokeGetIndex(tTarget, Dynamic.CoerceConvert(tIntIndexer,typeof(int))); else if (tStringIndexer != null) tTarget = InvokeGetIndex(tTarget, tStringIndexer); else { throw new Exception($"Could Not Parse :'{propertyChain}'"); } } return tTarget; } /// /// Determines whether the specified name on target is event. This allows you to know whether to InvokeMemberAction /// add_{name} or a combo of {invokeGet, +=, invokeSet} and the corresponding remove_{name} /// or a combo of {invokeGet, -=, invokeSet} /// /// The target. /// The name. /// /// true if the specified target is event; otherwise, false. /// public static bool InvokeIsEvent(object target, string name) { target = target.GetTargetContext(out var tContext, out var tStaticContext); tContext = tContext.FixContext(); CallSite tCallSite = null; return InvokeHelper.InvokeIsEventCallSite(target, name, tContext, ref tCallSite); } /// /// Invokes add assign with correct behavior for events. /// /// The target. /// The name. /// The value. public static void InvokeAddAssignMember(object target, string name, object value) { CallSite callSiteAdd =null; CallSite callSiteGet =null; CallSite callSiteSet =null; CallSite callSiteIsEvent = null; target = target.GetTargetContext(out var context, out var staticContext); var args = new[] { value }; args = Util.GetArgsAndNames(args, out var argNames); InvokeHelper.InvokeAddAssignCallSite(target, name, args, argNames, context, staticContext, ref callSiteIsEvent, ref callSiteAdd, ref callSiteGet, ref callSiteSet); } /// /// Invokes subtract assign with correct behavior for events. /// /// The target. /// The name. /// The value. public static void InvokeSubtractAssignMember(object target, string name, object value) { target = target.GetTargetContext(out var context, out var staticContext); var args = new[] { value }; args = Util.GetArgsAndNames(args, out var argNames); CallSite callSiteIsEvent = null; CallSite callSiteRemove = null; CallSite callSiteGet = null; CallSite callSiteSet = null; InvokeHelper.InvokeSubtractAssignCallSite(target, name, args, argNames, context, staticContext, ref callSiteIsEvent, ref callSiteRemove, ref callSiteGet,ref callSiteSet); } /// /// Invokes convert using the DLR. /// /// The target. /// The type. /// if set to true [explicit]. /// public static dynamic InvokeConvert(object target, Type type, bool @explicit =false) { target = target.GetTargetContext(out var tContext, out var tDummy); CallSite tCallSite =null; return InvokeHelper.InvokeConvertCallSite(target, @explicit, type, tContext, ref tCallSite); } internal static readonly IDictionary CompiledExpressions = new Dictionary(); /// /// Coerces any invokable to specified delegate type. /// /// The invokeable object. /// Type of the delegate. /// public static dynamic CoerceToDelegate(object invokeableObject, Type delegateType) { var delegateTypeInfo = delegateType.GetTypeInfo(); if (!typeof(Delegate).GetTypeInfo().IsAssignableFrom(delegateTypeInfo.BaseType)) { return null; } var tDelMethodInfo = delegateTypeInfo.GetMethod("Invoke"); if (tDelMethodInfo is null) { throw new Exception("This Delegate Didn't have and Invoke method! Impossible!"); } var tReturnType = tDelMethodInfo.ReturnType; var tAction = tReturnType == typeof(void); var tParams = tDelMethodInfo.GetParameters(); var tLength = tDelMethodInfo.GetParameters().Length; Delegate tBaseDelegate = tAction ? InvokeHelper.WrapAction(invokeableObject, tLength) : InvokeHelper.WrapFunc(tReturnType, invokeableObject, tLength); if (InvokeHelper.IsActionOrFunc(delegateType) && !tParams.Any(it => it.ParameterType.GetTypeInfo().IsValueType)) { return tBaseDelegate; } if (CompiledExpressions.TryGetValue(delegateType, out var tGetResult)) { return tGetResult.DynamicInvoke(tBaseDelegate); } var tParamTypes = tParams.Select(it => it.ParameterType).ToArray(); var tDelParam = Expression.Parameter(tBaseDelegate.GetType()); var tInnerParams = tParamTypes.Select(Expression.Parameter).ToArray(); var tI = Expression.Invoke(tDelParam, tInnerParams.Select(it => (Expression)Expression.Convert(it, typeof(object)))); var tL = Expression.Lambda(delegateType, tI, tInnerParams); tGetResult = Expression.Lambda(Expression.GetFuncType(tBaseDelegate.GetType(), delegateType), tL, tDelParam).Compile(); CompiledExpressions[delegateType] = tGetResult; return tGetResult.DynamicInvoke(tBaseDelegate); } private static readonly dynamic LateConvert = new DynamicObjects.LateType(typeof(Convert)); /// /// Determines whether value is DBNull dynamically (Useful for PCL) /// /// The value. /// /// true if [is DBNull]; otherwise, false. /// public static bool IsDBNull(object value) { try { return LateConvert.IsDBNull(value); } catch { return false; } } /// /// Applies the equivalent type hint to dynamic object /// /// The target. /// The types. public static void ApplyEquivalentType(DynamicObjects.IEquivalentType target, params Type[] types) { if(types.Length == 1) target.EquivalentType = types.First(); else target.EquivalentType = new DynamicObjects.AggreType(types.ConvertEach().ToArray()); } /// /// Implicit or Explicit Converts the items of the specified enumerable. /// /// /// The enumerable. /// if set to true [explicit]. /// [Obsolete("Use ConvertEach.")] public static IEnumerable ConvertAll(this System.Collections.IEnumerable enumerable, bool explict = false) => ConvertEach(enumerable, explict); /// /// Implicit or Explicit Converts the items of the specified enumerable. /// /// /// The enumerable. /// if set to true [explicit]. /// public static IEnumerable ConvertEach(this System.Collections.IEnumerable enumerable, bool @explicit =false) { return enumerable.Cast().Select(it => InvokeConvert(it, typeof (T), @explicit)).Cast(); } /// /// Goes the extra mile to convert target to type. /// /// The target. /// The type. /// public static dynamic CoerceConvert(object target, Type type) { var typeInfo = type.GetTypeInfo(); if (target != null && !typeInfo.IsInstanceOfType(target) && !IsDBNull(target)) { var delegateConversion = CoerceToDelegate(target, type); if (delegateConversion != null) return delegateConversion; if (typeInfo.IsInterface && Impromptu.IsAvailable) { if (target is IDictionary tDict && !(tDict is DynamicObjects.BaseObject)) { target = new DynamicObjects.Dictionary(tDict); } else if(!(target is DynamicObjects.BaseObject)) { target = new DynamicObjects.Get(target); } target = Impromptu.DynamicActLike(target, type); } else { try { object tResult = Dynamic.InvokeConvert(target, type, @explicit: true); target = tResult; } catch (RuntimeBinderException) { Type tReducedType = type; if (typeInfo.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { tReducedType = typeInfo.GetGenericArguments().First(); } if (typeof (Enum).GetTypeInfo().IsAssignableFrom(tReducedType) && target is string sVal) { target = Enum.Parse(tReducedType, sVal, true); } else if (target is IConvertible && typeof (IConvertible).GetTypeInfo().IsAssignableFrom(tReducedType)) { target = Convert.ChangeType(target, tReducedType, Net40.GetDefaultThreadCurrentCulture()); } else { try { dynamic converter = null; if (TypeDescriptor.IsAvailable) { converter = TypeDescriptor.GetConverter(tReducedType); } else if (TypeConverterAttributeSL != null) { var tAttributes = tReducedType.GetTypeInfo().GetCustomAttributes(TypeConverterAttributeSL, false); dynamic attribute = tAttributes.FirstOrDefault(); if (attribute != null) { converter = Impromptu.InvokeConstructor(Type.GetType(attribute.ConverterTypeName)); } } if (converter != null && converter.CanConvertFrom(target.GetType())) { target = converter.ConvertFrom(target); } } catch (RuntimeBinderException) { //This runtime converter block is a hail mary //lgtm [cs/empty-catch-block] } } } } } else if (((target == null) || IsDBNull(target )) && typeInfo.IsValueType) { target = Dynamic.InvokeConstructor(type); } else if (!typeInfo.IsInstanceOfType(target) && IsDBNull(target)) { return null; } return target; } /// /// Invokes the constructor. /// /// The type. /// The args. /// public static dynamic InvokeConstructor(Type type, params object[] args) { var tValue = type.GetTypeInfo().IsValueType; if (tValue && args.Length == 0) //dynamic invocation doesn't see constructors of value types { return Activator.CreateInstance(type); } args = Util.GetArgsAndNames( args, out var tArgNames); CallSite tCallSite = null; return InvokeHelper.InvokeConstructorCallSite(type, tValue, args, tArgNames, ref tCallSite); } /// /// FastDynamicInvoke extension method. Runs up to runs up to 20x faster than . /// /// The del. /// The args. /// public static object FastDynamicInvoke(this Delegate del, params object[] args) { if (del.GetMethodInfo().ReturnType != typeof(void)) { return InvokeHelper.FastDynamicInvokeReturn(del, args); } InvokeHelper.FastDynamicInvokeAction(del, args); return null; } /// /// Given a generic parameter count and whether it returns void or not gives type of Action or Func /// /// The param count. /// if set to true [return void]. /// Type of Action or Func public static Type GenericDelegateType(int paramCount, bool returnVoid = false) { var tParamCount = returnVoid ? paramCount : paramCount - 1; if (tParamCount > 16) throw new ArgumentException( $"{(returnVoid ? "Action" : "Func")} only handle at most {(returnVoid ? 16 : 17)} parameters", nameof(paramCount)); if(tParamCount < 0) throw new ArgumentException( $"{(returnVoid ? "Action" : "Func")} must have at least {(returnVoid ? 0 : 1)} parameter(s)", nameof(paramCount)); return returnVoid ? InvokeHelper.ActionKinds[tParamCount] : InvokeHelper.FuncKinds[tParamCount]; } /// /// Gets the member names of properties. Not all IDynamicMetaObjectProvider have support for this. /// /// The target. /// if set to true [dynamic only]. Won't add reflected properties /// public static IEnumerable GetMemberNames(object target, bool dynamicOnly = false) { var tList = new List(); if (!dynamicOnly) { tList.AddRange(target.GetType().GetTypeInfo().GetProperties().Select(it => it.Name)); } if (target is IDynamicMetaObjectProvider tTarget) { tList.AddRange(tTarget.GetMetaObject(Expression.Constant(tTarget)).GetDynamicMemberNames()); }else { if (ComObjectType != null && ComObjectType.GetTypeInfo().IsInstanceOfType(target) && ComBinder.IsAvailable) { tList.AddRange(ComBinder.GetDynamicDataMemberNames(target)); } } return tList; } /// /// Dynamically invokes a method determined by the CallSite binder and be given an appropriate delegate type /// /// The Callsite /// The target. /// The args. /// /// /// Advanced use only. Use this method for serious custom invocation, otherwise there are other convenience methods such as /// , , and /// public static dynamic InvokeCallSite(CallSite callSite, object target, params object[] args) { var tParameters = new List {callSite, target}; tParameters.AddRange(args); MulticastDelegate tDelegate = ((dynamic)callSite).Target; return tDelegate.FastDynamicInvoke(tParameters.ToArray()); } } } ================================================ FILE: Dynamitey/DynamicObjects/BaseDictionary.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.ComponentModel; using System.Dynamic; using System.Linq; using System.Reflection; using System.Threading; using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; namespace Dynamitey.DynamicObjects { /// /// Base class of Expando-Type objects /// public abstract class BaseDictionary : BaseObject, INotifyPropertyChanged { /// /// Wrapped Dictionary /// protected IDictionary _dictionary; /// /// Initializes a new instance of the class. /// /// The dict. protected BaseDictionary(IEnumerable> dict =null) { if (dict == null) { _dictionary = new Dictionary(); return; } if(dict is IDictionary) //Don't need to enumerate if it's the right type. _dictionary = (IDictionary)dict; else _dictionary = dict.ToDictionary(k => k.Key, v => v.Value); } /// /// Gets a value indicating whether this instance is read only. /// /// /// true if this instance is read only; otherwise, false. /// public virtual bool IsReadOnly => false; /// /// Gets the keys. /// /// The keys. public ICollection Keys => _dictionary.Keys; /// /// Gets the values. /// /// The values. public ICollection Values => _dictionary.Values; /// /// Returns the enumeration of all dynamic member names. /// /// /// A sequence that contains dynamic member names. /// public override IEnumerable GetDynamicMemberNames() { return base.GetDynamicMemberNames().Concat(_dictionary.Keys).Distinct(); } /// /// Provides the implementation for operations that get member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The result of the get operation. For example, if the method is called for a property, you can assign the property value to . /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) /// public override bool TryGetMember(GetMemberBinder binder, out object result) { if (_dictionary.TryGetValue(binder.Name, out result)) { return this.MassageResultBasedOnInterface(binder.Name, true, ref result); } result = null; return this.MassageResultBasedOnInterface(binder.Name, false, ref result); } /// /// Provides the implementation for operations that invoke a member. Classes derived from the class can override this method to specify dynamic behavior for operations such as calling a method. /// /// Provides information about the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleMethod". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The arguments that are passed to the object member during the invoke operation. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is derived from the class, is equal to 100. /// The result of the member invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if (_dictionary.TryGetValue(binder.Name, out result)) { var tFunc = result as Delegate; if (result == null) return false; if (!binder.CallInfo.ArgumentNames.Any() && tFunc != null) { try { result = this.InvokeMethodDelegate(tFunc, args); } catch (RuntimeBinderException)//If it has out parmaters etc it can't be invoked dynamically like this. //if we return false it will be handle by the GetProperty and then handled by the original dynamic invocation { return false; } } else { try { result = Dynamic.Invoke(result, Util.NameArgsIfNecessary(binder.CallInfo, args)); } catch (RuntimeBinderException) //If it has out parmaters etc it can't be invoked dynamically like this. //if we return false it will be handle by the GetProperty and then handled by the original dynamic invocation { return false; } } return this.MassageResultBasedOnInterface(binder.Name, true, ref result); } return this.MassageResultBasedOnInterface(binder.Name, false, ref result); } /// /// Provides the implementation for operations that set member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as setting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member to which the value is being assigned. For example, for the statement sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The value to set to the member. For example, for sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the class, the is "Test". /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TrySetMember(SetMemberBinder binder, object value) { SetProperty(binder.Name,value); return true; } /// /// Adds the specified item. /// /// The item. public void Add(KeyValuePair item) { SetProperty(item.Key, item.Value); } /// /// Determines whether [contains] [the specified item]. /// /// The item. /// /// true if [contains] [the specified item]; otherwise, false. /// public bool Contains(KeyValuePair item) { return _dictionary.Contains(item); } /// /// Copies to. /// /// The array. /// Index of the array. public void CopyTo(KeyValuePair[] array, int arrayIndex) { _dictionary.CopyTo(array,arrayIndex); } /// /// Removes the specified item. /// /// The item. /// public bool Remove(KeyValuePair item) { if (TryGetValue(item.Key, out var tValue)) { if (item.Value == tValue) { Remove(item.Key); } } return false; } /// /// Determines whether the specified key contains key. /// /// The key. /// /// true if the specified key contains key; otherwise, false. /// public bool ContainsKey(string key) { return _dictionary.ContainsKey(key); } /// /// Adds the specified key. /// /// The key. /// The value. public void Add(string key, object value) { SetProperty(key,value); } /// /// Removes the specified key. /// /// The key. /// public bool Remove(string key) { var tReturn = _dictionary.Remove(key); OnPropertyChanged(key); return tReturn; } /// /// Tries the get value. /// /// The key. /// The value. /// public bool TryGetValue(string key, out object value) { return _dictionary.TryGetValue(key, out value); } /// /// Sets the property. /// /// The key. /// The value. protected void SetProperty(string key, object value) { if (!_dictionary.TryGetValue(key, out var tOldValue) || value != tOldValue) { _dictionary[key] = value; OnPropertyChanged(key); } } /// /// Called when [property changed]. /// /// The key. protected virtual void OnPropertyChanged(string key) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(key)); #if SILVERLIGHT PropertyChanged(this, new PropertyChangedEventArgs("Item["+key+"]")); //Indexers are Updated on Dictionarys as well #else PropertyChanged(this, new PropertyChangedEventArgs("Item[]")); //Indexers are Updated on Dictionarys as well WPF does not support Item[key] syntax #endif } } /// /// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; /// /// Equalses the specified other. /// /// The other. /// public bool Equals(Dictionary other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(other._dictionary, _dictionary); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != typeof (Dictionary)) return _dictionary.Equals(obj); return Equals((Dictionary) ((object) ((Dictionary) obj))); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { return _dictionary.GetHashCode(); } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return _dictionary.ToString(); } } } ================================================ FILE: Dynamitey/DynamicObjects/BaseForwarder.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Reflection; using System.Text; using Dynamitey.Internal.Optimization; using Microsoft.CSharp; using Microsoft.CSharp.RuntimeBinder; namespace Dynamitey.DynamicObjects { /// /// An proxy object /// public interface IForwarder { /// /// Gets the target. /// /// The target. object Target { get; } } /// /// Proxies Calls allows subclasser to override do extra actions before or after base invocation /// /// /// This may not be as efficient as other proxies that can work on just static objects or just dynamic objects... /// Consider this when using. /// public abstract class BaseForwarder : BaseObject, IForwarder { /// /// Marks whether we are adding or removing the delegate /// public class AddRemoveMarker { /// /// Implements the operator +. /// /// The left. /// The right. /// The result of the operator. public static AddRemoveMarker operator +(AddRemoveMarker left, object right) { left.Delegate = right; left.IsAdding = true; return left; } /// /// Implements the operator -. /// /// The left. /// The right. /// The result of the operator. public static AddRemoveMarker operator -(AddRemoveMarker left, object right) { left.Delegate = right; left.IsAdding = false; return left; } /// /// Gets or sets the delegate. /// /// The delegate. public object Delegate { get; protected set; } /// /// Gets or sets a value indicating whether this instance is adding. /// /// true if this instance is adding; otherwise, false. public bool IsAdding { get; protected set; } } /// /// Initializes a new instance of the class. /// /// The target. protected BaseForwarder(object target) { Target = target; } /// /// Returns the enumeration of all dynamic member names. /// /// /// A sequence that contains dynamic member names. /// public override IEnumerable GetDynamicMemberNames() { var tDyanmic = Dynamic.GetMemberNames(CallTarget, dynamicOnly: true); if (!tDyanmic.Any()) { return Dynamic.GetMemberNames(CallTarget); } return base.GetDynamicMemberNames(); } /// /// Gets or sets the target. /// /// The target. protected object Target { get; set; } object IForwarder.Target => Target; /// /// Gets the call target. /// /// The call target. protected virtual object CallTarget => Target; /// /// Provides the implementation for operations that get member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The result of the get operation. For example, if the method is called for a property, you can assign the property value to . /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) /// public override bool TryGetMember(GetMemberBinder binder, out object result) { if (CallTarget == null) { result = null; return false; } if (Dynamic.InvokeIsEvent(CallTarget, binder.Name)) { result = new AddRemoveMarker(); return true; } try { result = Dynamic.InvokeGet(CallTarget, binder.Name); } catch (RuntimeBinderException) { result = null; return false; } return true; } #pragma warning disable 1734 /// /// Provides the implementation for operations that invoke an object. Classes derived from the class can override this method to specify dynamic behavior for operations such as invoking an object or a delegate. /// /// Provides information about the invoke operation. /// The arguments that are passed to the object during the invoke operation. For example, for the sampleObject(100) operation, where sampleObject is derived from the class, is equal to 100. /// The result of the object invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown. /// #pragma warning restore 1734 public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { if (CallTarget == null) { result = null; return false; } var tArgs = Util.NameArgsIfNecessary(binder.CallInfo, args); try { result = Dynamic.Invoke(CallTarget, tArgs); } catch (RuntimeBinderException) { result = null; try { Dynamic.InvokeAction(CallTarget, tArgs); } catch (RuntimeBinderException) { return false; } } return true; } /// /// Tries the invoke member. /// /// The binder. /// The args. /// The result. /// public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if (CallTarget == null) { result = null; return false; } object[] tArgs = Util.NameArgsIfNecessary(binder.CallInfo, args); Type[] types = null; try { //.net core // Try and pull generic arguments from binder IList typeList = Dynamic.InvokeGet(binder, "TypeArguments"); if (typeList != null) { types = typeList.ToArray(); } } catch (RuntimeBinderException) { types = null; } if (types == null) { try { //.net 4.0 // Try and pull generic arguments from binder IList typeList = Dynamic.InvokeGet(binder, "Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments"); if (typeList != null) { types = typeList.ToArray(); } } catch (RuntimeBinderException) { types = null; } } var name = InvokeMemberName.Create; var fullName = name(binder.Name, types); try { result = Dynamic.InvokeMember(CallTarget, fullName, tArgs); } catch (RuntimeBinderException) { result = null; try { Dynamic.InvokeMemberAction(CallTarget, fullName, tArgs); } catch (RuntimeBinderException) { return false; } } return true; } /// /// Tries the set member. /// /// The binder. /// The value. /// public override bool TrySetMember(SetMemberBinder binder, object value) { if (CallTarget == null) { return false; } if (Dynamic.InvokeIsEvent(CallTarget, binder.Name) && value is AddRemoveMarker arm) { if (arm.IsAdding) { Dynamic.InvokeAddAssignMember(CallTarget, binder.Name, arm.Delegate); } else { Dynamic.InvokeSubtractAssignMember(CallTarget, binder.Name, arm.Delegate); } return true; } try { Dynamic.InvokeSet(CallTarget, binder.Name, value); return true; } catch (RuntimeBinderException) { return false; } } /// /// Tries the index of the get. /// /// The binder. /// The indexes. /// The result. /// public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (CallTarget == null) { result = null; return false; } object[] tArgs = Util.NameArgsIfNecessary(binder.CallInfo, indexes); try { result = Dynamic.InvokeGetIndex(CallTarget, tArgs); return true; } catch (RuntimeBinderException) { result = null; return false; } } /// /// Tries the index of the set. /// /// The binder. /// The indexes. /// The value. /// public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { if (CallTarget == null) { return false; } var tCombinedArgs = indexes.Concat(new[] { value }).ToArray(); object[] tArgs = Util.NameArgsIfNecessary(binder.CallInfo, tCombinedArgs); try { Dynamic.InvokeSetIndex(CallTarget, tArgs); return true; } catch (RuntimeBinderException) { return false; } } /// /// Equals the specified other. /// /// The other. /// public bool Equals(BaseForwarder other) { if (ReferenceEquals(null, other)) return ReferenceEquals(null, CallTarget); if (ReferenceEquals(this, other)) return true; return Equals(other.CallTarget, CallTarget); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return ReferenceEquals(null, CallTarget); if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != typeof (BaseForwarder)) return false; return Equals((BaseForwarder) obj); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { return (CallTarget != null ? CallTarget.GetHashCode() : 0); } } } ================================================ FILE: Dynamitey/DynamicObjects/BaseObject.cs ================================================ // // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.ComponentModel; using System.Dynamic; using System.Linq; using System.Reflection; using Dynamitey.Internal.Compat; namespace Dynamitey.DynamicObjects { /// /// Can Represent an equivalent static type to help dynamically convert member output /// public interface IEquivalentType { /// /// Gets or sets the type of the equivalent. /// /// /// The type of the equivalent. /// FauxType EquivalentType { get; set; } } /// /// Dynamic Object that knows about the Impromtu Interface return types; /// Override Typical Dynamic Object methods, and use TypeForName to get the return type of an interface member. /// public abstract class BaseObject : DynamicObject, IEquivalentType { /// /// Initializes a new instance of the class. /// protected BaseObject() { } /// /// Tries the name of the member to see if it has a type. /// /// Name of the binder. /// The type. /// public bool TryTypeForName(string binderName, out Type type) { var eqType = (IEquivalentType) this; type = null; if (eqType.EquivalentType == null) return false; var types = eqType.EquivalentType.GetMember(binderName) .Select(it => { switch (it) { case PropertyInfo p: return p.PropertyType; case MethodInfo m: return m.ReturnType; case EventInfo e: return e.EventHandlerType; #if NETFRAMEWORK || PROFILE158 case Type t: return t; #else case TypeInfo t: return t.UnderlyingSystemType; #endif default: return typeof (object); } }).ToList(); ; if (!types.Any()) return false; foreach (var currenttype in types) { if (type == null || type.Name == currenttype.Name) type = currenttype; else type = typeof (object); } return true; } FauxType IEquivalentType.EquivalentType { get; set; } } } ================================================ FILE: Dynamitey/DynamicObjects/Builder.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Text; using System.Reflection; using Dynamitey.Internal.Optimization; using Dynamitey.Internal.Compat; namespace Dynamitey.DynamicObjects { /// /// Interface for simplistic builder options /// public interface IBuilder { /// /// Creates a prototype list /// /// The contents. /// dynamic List(params dynamic[] contents); /// /// Setup List or Array, takes either one or a list of constructor args that will use objects Type /// /// The constructor args. /// dynamic ListSetup(params dynamic[] constructorArgs); /// /// Setup List or Array if list has a default constrcutor /// /// /// dynamic ListSetup(); /// /// Setup List or Array, takes either one or a list of constructor args that will use objects Type /// /// The constructor args factory. /// dynamic ListSetup(Func constructorArgsFactory); /// /// Setup List or Array if list has a default constrcutor /// /// /// dynamic ArraySetup(); /// /// Alternative name for /// /// The constructor args. /// dynamic ArraySetup(params dynamic[] constructorArgs); /// /// Alternative name for /// /// The constructor args factory. /// dynamic ArraySetup(Func constructorArgsFactory); /// /// Alternative name for /// /// The contents. /// dynamic Array(params dynamic[] contents); /// /// Generates Object, use by calling with named arguments builder.Object(Prop1:"test",Prop2:"test") /// returns new object; /// dynamic Object { get; } /// /// Sets up object builder /// /// The constructor args. /// dynamic ObjectSetup(params dynamic[] constructorArgs); /// /// Sets up object builder /// /// /// dynamic ObjectSetup(Func constructorArgsFactory); /// /// Setups up named builders /// /// The setup. dynamic Setup { get; } } /// /// Builds Expando-Like Objects with an inline Syntax /// /// The type of the object proto type. public class Builder: BaseObject, IBuilder { /// /// Build factory storage /// protected IDictionary _buildType; /// /// Initializes a new instance of the class. /// public Builder(){ _buildType = new Dictionary(); Setup = new SetupTrampoline(this); Object = new BuilderTrampoline(this); } /// /// Creates a prototype list /// /// The contents. /// public dynamic List(params dynamic[] contents) { if (!_buildType.TryGetValue("List", out var tBuildType)) tBuildType = null; if (tBuildType != null) { dynamic tList = tBuildType.Create(); if (contents != null) { foreach (var item in contents) { tList.Add(item); } } return tList; } return new List(contents); } /// /// Setup List or Array, takes either one or a list of constructor args that will use objects Type /// /// The constructor args. /// public dynamic ListSetup(params dynamic[] constructorArgs) { var tActivate =constructorArgs.OfType().SingleOrDefault(); if (tActivate == null) { if (!_buildType.TryGetValue("Object", out tActivate)) tActivate = null; if (tActivate != null) { tActivate = new Activate(tActivate.Type,constructorArgs); } if(tActivate == null) tActivate = new Activate(constructorArgs); } _buildType["List"] = tActivate; _buildType["Array"] = tActivate; return this; } /// /// Setup List or Array if list has a default constrcutor /// /// /// public dynamic ListSetup() { return ListSetup(new Activate()); } /// /// Setup List or Array, takes either one or a list of constructor args that will use objects Type /// /// The constructor args factory. /// public dynamic ListSetup(Func constructorArgsFactory) { return ListSetup((object)constructorArgsFactory); } /// /// Setup List or Array if list has a default constrcutor /// /// /// public dynamic ArraySetup() { return ListSetup(new Activate()); } /// /// Alternative name for /// /// The constructor args. /// public dynamic ArraySetup(params dynamic[] constructorArgs) { return ListSetup(constructorArgs); } /// /// Alternative name for /// /// The constructor args factory. /// public dynamic ArraySetup(Func constructorArgsFactory) { return ListSetup((object)constructorArgsFactory); } /// /// Alternative name for /// /// The contents. /// public dynamic Array(params dynamic[] contents) { return List(contents); } /// /// Creates a Prototype object. /// /// The object. public dynamic Object { get; } /// /// Sets up object builder /// /// The constructor args. /// public dynamic ObjectSetup(params dynamic[] constructorArgs) { _buildType["Object"] = new Activate(constructorArgs); return this; } /// /// Sets up object builder /// /// /// public dynamic ObjectSetup(Func constructorArgsFactory) { return ObjectSetup((object) constructorArgsFactory); } /// /// Trapoline for setting up Builders /// public dynamic Setup { get; private set; } /// /// Trampoline for builder /// public class BuilderTrampoline : DynamicObject { Builder _buider; /// /// Initializes a new instance of the class. /// /// The builder. public BuilderTrampoline(Builder builder) { _buider = builder; } /// /// Tries the invoke. /// /// The binder. /// The args. /// The result. /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { if (!_buider._buildType.TryGetValue("Object", out var tBuildType)) tBuildType = null; result = InvokeHelper(binder.CallInfo, args, tBuildType); return true; } } /// /// Trampoline for setup builder /// public class SetupTrampoline : DynamicObject { Builder _buider; /// /// Initializes a new instance of the class. /// /// The builder. public SetupTrampoline(Builder builder){ _buider = builder; } /// /// Tries the invoke. /// /// The binder. /// The args. /// The result. /// /// Requires argument names for every argument public override bool TryInvoke(InvokeBinder binder, dynamic[] args, out object result) { if (binder.CallInfo.ArgumentNames.Count != binder.CallInfo.ArgumentCount) throw new ArgumentException("Requires argument names for every argument"); var tArgs = args.Select(it => it is Type ? new Activate(it) : (Activate) it); foreach (var tKeyPair in binder.CallInfo.ArgumentNames.Zip(tArgs, (n, a) => new KeyValuePair(n, a))) { _buider._buildType[tKeyPair.Key]=tKeyPair.Value; } result = _buider; return true; } } /// /// Tries the set member. /// /// The binder. /// The value. /// public override bool TrySetMember(SetMemberBinder binder, dynamic value){ if (value != null) { if (value is Type) { _buildType[binder.Name] = new Activate(value); return true; } if (value is Activate) { _buildType[binder.Name] = value; return true; } } else { _buildType[binder.Name] = null; return true; } return false; } /// /// Tries the invoke member. /// /// The binder. /// The args. /// The result. /// public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if(!_buildType.TryGetValue(binder.Name, out var tBuildType)) tBuildType = null; if (tBuildType == null && !_buildType.TryGetValue("Object", out tBuildType)) tBuildType = null; result = InvokeHelper(binder.CallInfo, args,tBuildType); if (TryTypeForName(binder.Name, out var tType)) { var typeInfo = tType.GetTypeInfo(); if (Dynamic.Impromptu.IsAvailable && typeInfo.IsInterface && result != null && !typeInfo.IsAssignableFrom(result.GetType())) { result = Dynamic.Impromptu.DynamicActLike(result, tType); } } return true; } private static object InvokeHelper(CallInfo callinfo, IList args, Activate buildType =null) { bool tSetWithName = true; object tArg = null; if (callinfo.ArgumentNames.Count == 0 && callinfo.ArgumentCount == 1) { tArg =args[0]; if (Util.IsAnonymousType(tArg) || tArg is IEnumerable>) { tSetWithName = false; } } if (tSetWithName && callinfo.ArgumentNames.Count != callinfo.ArgumentCount) throw new ArgumentException("Requires argument names for every argument"); object result; if (buildType != null) { result = buildType.Create(); } else{ try { result = Activator.CreateInstance();//Try first because faster but doens't work with optional parameters } catch (Exception) { result = Dynamic.InvokeConstructor(typeof (TObjectProtoType)); } } if(tSetWithName) { tArg = callinfo.ArgumentNames.Zip(args, (n, a) => new KeyValuePair(n, a)); } return Dynamic.InvokeSetAll(result, tArg); } } } ================================================ FILE: Dynamitey/DynamicObjects/Dictionary.cs ================================================  // // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Dynamic; using System.Linq; using System.Reflection; namespace Dynamitey.DynamicObjects { /// /// Similar to Expando Objects but handles null values when the property is defined with an impromptu interface /// public class Dictionary:BaseDictionary,IDictionary { /// /// Initializes a new instance of the class. /// public Dictionary() { } /// /// Initializes a new instance of the class. /// /// The dict. public Dictionary(IEnumerable> dict) : base(dict) { } /// /// Gets the count. /// /// The count. public int Count => _dictionary.Count; /// /// Gets the enumerator. /// /// public IEnumerator> GetEnumerator() { return _dictionary.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Clears this instance. /// public void Clear() { var tKeys = Keys; _dictionary.Clear(); foreach (var tKey in tKeys) { OnPropertyChanged(tKey); } } /// /// Gets or sets the with the specified key. /// /// public object this[string key] { get => _dictionary[key]; set => SetProperty(key, value); } } /// /// Adds extra synatx to intialize properties to match up with clay /// public class ChainableDictionary:Dictionary{ /// /// Initializes a new instance of the class. /// public ChainableDictionary() { } /// /// Initializes a new instance of the class. /// /// The dict. public ChainableDictionary(IEnumerable> dict) : base(dict) { } /// /// Provides the implementation for operations that invoke a member. Classes derived from the class can override this method to specify dynamic behavior for operations such as calling a method. /// /// Provides information about the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleMethod". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The arguments that are passed to the object member during the invoke operation. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is derived from the class, is equal to 100. /// The result of the member invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryInvokeMember (InvokeMemberBinder binder, object[] args, out object result) { if(base.TryInvokeMember (binder, args, out result)){ return true; } if(binder.CallInfo.ArgumentCount ==1){ SetProperty(binder.Name, args.FirstOrDefault()); result = this; return true; } if (binder.CallInfo.ArgumentCount > 1) { SetProperty(binder.Name,new List(args)); result = this; return true; } return false; } } } ================================================ FILE: Dynamitey/DynamicObjects/Dummy.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Dynamitey.Internal.Optimization; namespace Dynamitey.DynamicObjects { /// /// Dummy that just returns null or default for everything. /// public class Dummy:BaseObject { /// /// Initializes a new instance of the class. /// public Dummy() { } /// /// Provides the implementation for operations that get member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The result of the get operation. For example, if the method is called for a property, you can assign the property value to . /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) /// public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) { result = null; return this.MassageResultBasedOnInterface(binder.Name, true, ref result); } /// /// Provides the implementation for operations that set member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as setting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member to which the value is being assigned. For example, for the statement sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The value to set to the member. For example, for sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the class, the is "Test". /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value) { return true; } /// /// Provides the implementation for operations that invoke a member. Classes derived from the class can override this method to specify dynamic behavior for operations such as calling a method. /// /// Provides information about the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleMethod". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The arguments that are passed to the object member during the invoke operation. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is derived from the class, is equal to 100. /// The result of the member invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) { result = null; return this.MassageResultBasedOnInterface(binder.Name, true, ref result); } /// /// Tries the index of the get. /// /// The binder. /// The indexes. /// The result. /// public override bool TryGetIndex(System.Dynamic.GetIndexBinder binder, object[] indexes, out object result) { result = null; return this.MassageResultBasedOnInterface(Invocation.IndexBinderName, true, ref result); } /// /// Tries the index of the set. /// /// The binder. /// The indexes. /// The value. /// public override bool TrySetIndex(System.Dynamic.SetIndexBinder binder, object[] indexes, object value) { return true; } } } ================================================ FILE: Dynamitey/DynamicObjects/ExtensionToInstanceProxy.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Reflection; using System.Text; using Microsoft.CSharp.RuntimeBinder; using Dynamitey.Internal.Compat; using Dynamitey.Internal.Optimization; namespace Dynamitey.DynamicObjects { /// /// Proxy that can turn extension methods into instance methods /// public class ExtensionToInstanceProxy: BaseForwarder { private readonly Type _extendedType; private readonly Type[] _staticTypes; private readonly Type[] _instanceHints; /// /// Gets the instance hints. /// /// /// The instance hints. /// public IEnumerable InstanceHints => _instanceHints; /// /// Initializes a new instance of the class. /// /// The target. /// Type of the extended. /// The static types. /// The instance hints. /// Don't Nest ExtensionToInstance Objects public ExtensionToInstanceProxy(dynamic target, Type extendedType, Type[] staticTypes, Type[] instanceHints = null):base((object)target) { _staticTypes = staticTypes; _extendedType = extendedType; _instanceHints = instanceHints; if(target is ExtensionToInstanceProxy) throw new ArgumentException("Don't Nest ExtensionToInstance Objects"); if (IsExtendedType(target) || IsExtendedType(Util.GetTargetContext(target,out Type _, out bool _))) { return; } throw new ArgumentException($"Non a valid {_extendedType} to be wrapped."); } private object UnwrappedTarget(){ return Util.GetTargetContext(CallTarget, out Type _, out bool _); } /// /// Provides the implementation for operations that get member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The result of the get operation. For example, if the method is called for a property, you can assign the property value to . /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) /// public override bool TryGetMember(GetMemberBinder binder, out object result) { if (!base.TryGetMember(binder, out result)) { var tInterface = UnwrappedTarget().GetType().GetTypeInfo().GetInterfaces().Single(it => it.Name == _extendedType.Name); var typeInfo = tInterface.GetTypeInfo(); result = new Invoker(binder.Name, typeInfo.IsGenericType ? typeInfo.GetGenericArguments() : new Type[] {},null, this); } return true; } /// /// Basic Invoker syntax for dynamic generics /// public class Invoker:BaseObject { /// /// The name /// protected string Name; /// /// The parent /// protected ExtensionToInstanceProxy Parent; /// /// The overload types /// protected IDictionary OverloadTypes; /// /// The generic params /// protected Type[] GenericParams; /// /// The generic method parameters /// protected Type[] GenericMethodParameters; internal Invoker(string name, Type[] genericParameters, Type[] genericMethodParameters, ExtensionToInstanceProxy parent, Type[] overloadTypes = null) { Name = name; Parent = parent; GenericParams = genericParameters; GenericMethodParameters = genericMethodParameters; OverloadTypes = new Dictionary(); if (overloadTypes == null) { foreach (var tGenInterface in parent.InstanceHints) { var tNewType = tGenInterface; if (tNewType.GetTypeInfo().IsGenericType) { tNewType = tNewType.MakeGenericType(GenericParams); } var members = tNewType.GetTypeInfo().GetMethods(BindingFlags.Instance | BindingFlags.Public).Where( it => it.Name == Name).ToList(); foreach (var tMethodInfo in members) { var tParams = tMethodInfo.GetParameters().Select(it => it.ParameterType).ToArray(); if (OverloadTypes.ContainsKey(tParams.Length)) { OverloadTypes[tParams.Length] = new Type[] {}; } else { OverloadTypes[tParams.Length] = tParams.Select(ReplaceGenericTypes).ToArray(); } } foreach (var tOverloadType in OverloadTypes.ToList()) { if (tOverloadType.Value.Length == 0) { OverloadTypes.Remove(tOverloadType); } } } } else { OverloadTypes[overloadTypes.Length] = overloadTypes; } } private Type ReplaceGenericTypes(Type type) { var typeInfo = type.GetTypeInfo(); if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters) { var tArgs = typeInfo.GetGenericArguments(); tArgs = tArgs.Select(ReplaceGenericTypes).ToArray(); return type.GetGenericTypeDefinition().MakeGenericType(tArgs); } if (typeInfo.ContainsGenericParameters) { return typeof (object); } return type; } /// /// Tries the get member. /// /// The binder. /// The result. /// public override bool TryGetMember(GetMemberBinder binder, out object result) { if (binder.Name == "Overloads") { result = new OverloadInvoker(Name, GenericParams,GenericMethodParameters, Parent); return true; } return base.TryGetMember(binder, out result); } /// /// Tries the invoke. /// /// The binder. /// The args. /// The result. /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { object[] tArgs = args; if (OverloadTypes.ContainsKey(args.Length)) { tArgs = OverloadTypes[args.Length].Zip(args, Tuple.Create) .Select(it => it.Item2 != null ? Dynamic.InvokeConvert(it.Item2, it.Item1, @explicit: true) : null).ToArray(); } var name = InvokeMemberName.Create(Name, GenericMethodParameters); result = Parent.InvokeStaticMethod(name, tArgs); return true; } /// /// Tries the index of the get. /// /// The binder. /// The indexes. /// The result. /// public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { result = new Invoker(Name, GenericParams, indexes.Select(it => Dynamic.InvokeConvert(it, typeof(Type), @explicit: true)).Cast().ToArray(), Parent); return true; } } /// /// Overload Invoker /// public class OverloadInvoker:Invoker { internal OverloadInvoker(string name, Type[] genericParameters, Type[] genericMethodParameters, ExtensionToInstanceProxy parent) : base(name, genericParameters,genericMethodParameters, parent) { } /// /// Tries the index of the get. /// /// The binder. /// The indexes. /// The result. /// public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { result = new Invoker(Name, GenericParams, GenericMethodParameters, Parent, indexes.Select(it => Dynamic.InvokeConvert(it, typeof(Type), @explicit: true)).Cast().ToArray()); return true; } } /// /// Tries the invoke member. /// /// The binder. /// The args. /// The result. /// public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) { if (!base.TryInvokeMember(binder, args, out result)) { Type[] types = null; try { IList typeList =Dynamic.InvokeGet(binder, "Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments"); if(typeList != null) { types = typeList.ToArray(); } }catch(RuntimeBinderException) { try { IList typeList = Dynamic.InvokeGet(binder, "TypeArguments"); if (typeList != null) { types = typeList.ToArray(); } } catch (RuntimeBinderException) { types = null; } } var name=InvokeMemberName.Create; result = InvokeStaticMethod(name(binder.Name, types), args); } return true; } /// /// Invokes the static method. /// /// The name. /// The args. /// protected object InvokeStaticMethod(String_OR_InvokeMemberName name, object[] args) { var staticType = InvokeContext.CreateStatic; var nameArgs = InvokeMemberName.Create; var tList = new List { UnwrappedTarget() }; tList.AddRange(args); object result =null; var sucess = false; var exceptionList = new List(); var tGenericPossibles = new List(); if (name.GenericArgs != null && name.GenericArgs.Length > 0) { var tInterface = UnwrappedTarget().GetType().GetTypeInfo().GetInterfaces().Single(it => it.Name == _extendedType.Name); var tTypeGenerics = (tInterface.GetTypeInfo().IsGenericType ? tInterface.GetTypeInfo().GetGenericArguments() : new Type[] { }).Concat(name.GenericArgs).ToArray(); tGenericPossibles.Add(tTypeGenerics); tGenericPossibles.Add(name.GenericArgs); } else { tGenericPossibles.Add(null); } foreach (var sType in _staticTypes) { foreach (var tGenericPossible in tGenericPossibles) { try { result = Dynamic.InvokeMember(staticType(sType), nameArgs(name.Name, tGenericPossible), tList.ToArray()); sucess = true; break; } catch (RuntimeBinderException ex) { exceptionList.Add(ex); } } if(sucess){ break; } } if (!sucess) { throw exceptionList.First(); } if (TryTypeForName(name.Name, out var tOutType)) { var outTypeInfo = tOutType.GetTypeInfo(); if (outTypeInfo.IsInterface) { var tIsGeneric = outTypeInfo.IsGenericType; if (outTypeInfo.IsGenericType) { tOutType = tOutType.GetGenericTypeDefinition(); } if (InstanceHints.Select(it => tIsGeneric && it.GetTypeInfo().IsGenericType ? it.GetGenericTypeDefinition() : it) .Any(it=> it.Name == tOutType.Name)) { result = CreateSelf(result, _extendedType, _staticTypes, _instanceHints); } } } else { if (IsExtendedType(result)) { result = CreateSelf(result, _extendedType, _staticTypes, _instanceHints); } } return result; } /// /// Creates the self. /// /// The target. /// Type of the extended. /// The static types. /// The instance hints. /// protected virtual ExtensionToInstanceProxy CreateSelf(object target, Type extendedType, Type[] staticTypes, Type[] instanceHints) { return new ExtensionToInstanceProxy(target,extendedType,staticTypes, instanceHints); } private bool IsExtendedType(object target) { if (target is ExtensionToInstanceProxy) { return false; } bool genericDef = _extendedType.GetTypeInfo().IsGenericTypeDefinition; return target.GetType().GetTypeInfo().GetInterfaces().Any( it => ((genericDef && it.GetTypeInfo().IsGenericType) ? it.GetGenericTypeDefinition() : it).Name == _extendedType.Name); } } } ================================================ FILE: Dynamitey/DynamicObjects/Factory.cs ================================================ // // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; namespace Dynamitey.DynamicObjects { /// /// Base Class for making a fluent factory using an Impromptu Interface return type. /// public class BaseFactory:BaseObject { /// /// Provides the default implementation for operations that get instance as defined by . Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The result of the get operation. For example, if the method is called for a property, you can assign the property value to . /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) /// public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) { result = GetInstanceForDynamicMember(binder.Name); return result != null; } /// /// Provides the implementation for operations that invoke a member. Classes derived from the class can override this method to specify dynamic behavior for operations such as calling a method. /// /// Provides information about the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleMethod". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The arguments that are passed to the object member during the invoke operation. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is derived from the class, [0] is equal to 100. /// The result of the member invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) { result = GetInstanceForDynamicMember(binder.Name, args); return result != null; } /// /// Constructs the type. Override for changing type intialization property changes. /// /// The type. /// The args. /// protected virtual object CreateType(Type type, params object[] args) { return Dynamic.InvokeConstructor(type, args); } /// /// Gets the instance for a dynamic member. Override for type constrcution behavoir changes based on property name. /// /// Name of the member. /// The args. /// protected virtual object GetInstanceForDynamicMember(string memberName, params object[] args) { return TryTypeForName(memberName, out var type) ? CreateType(type, args) : null; } } /// /// Base Class for making a singleton fluent factory using an Impromptu Interface return type. /// public class BaseSingleInstancesFactory : BaseFactory { /// /// Store Singletons /// protected readonly Dictionary _hashFactoryTypes= new Dictionary(); /// /// Lock for accessing singletons /// protected readonly object _lockTable = new object(); /// /// Gets the instance for a dynamic member. Override for type constrcution behavoir changes based on property name. /// /// Name of the member. /// /// protected override object GetInstanceForDynamicMember(string memberName, params object[] args) { lock (_lockTable) { if (!_hashFactoryTypes.ContainsKey(memberName)) { if (TryTypeForName(memberName, out var type)) { _hashFactoryTypes.Add(memberName, CreateType(type, args)); } else { return null; } } return _hashFactoryTypes[memberName]; } } } } ================================================ FILE: Dynamitey/DynamicObjects/FauxType.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Dynamitey.Internal.Compat; namespace Dynamitey.DynamicObjects { /// /// A Fake Type /// public abstract class FauxType { /// /// Fauxes the type. /// /// The type. /// public static implicit operator FauxType(Type type) { return new RealType(type); } /// /// Gets the members. /// /// Name of the binder. /// public abstract IEnumerable GetMember(string binderName); /// /// Gets the contained types. /// /// public abstract Type[] GetContainedTypes(); public abstract IEnumerable GetMemberNames(); /// /// Determines whether the specified type contains the type. /// /// The type. /// /// true if the specified type contains type; otherwise, false. /// public virtual bool ContainsType(Type type) { return GetContainedTypes().Contains(type); } } public class PropretySpecType : FauxType { public IDictionary PropertySpec { get; } public PropretySpecType(IDictionary propertySpec) { PropertySpec = propertySpec; } public override IEnumerable GetMember(string binderName) { if (PropertySpec.TryGetValue(binderName, out var val)) { return new[] {val.GetTypeInfo()}; } return Enumerable.Empty(); } public override IEnumerable GetMemberNames() { return PropertySpec.Keys; } public override Type[] GetContainedTypes() { return new Type []{}; } } /// /// A Fake Type that represents a real type /// public class RealType : FauxType { /// /// RealType implicitly conversts to an actualy Type /// /// The type. /// public static implicit operator Type(RealType type) { return type.TargetType; } /// /// An actual Type implicitly conversts to a real type /// /// The type. /// public static implicit operator RealType(Type type) { return new RealType(type); } /// /// The target type /// protected readonly Type TargetType; /// /// Initializes a new instance of the class. /// /// The type. public RealType(Type type) { TargetType = type; } /// /// Gets the members. /// /// Name of the binder. /// public override IEnumerable GetMember(string binderName) { return TargetType.GetTypeInfo().GetMember(binderName); } public override IEnumerable GetMemberNames() { var members = TargetType.GetTypeInfo() .GetMembers(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance) .Where(it=> !((it as MethodInfo)?.IsHideBySig ?? false)) .Select(it => it.Name) .Distinct(); return members.ToList(); } /// /// Gets the contained types. /// /// public override Type[] GetContainedTypes() { return new[] { TargetType }; } } /// /// A Fake Tupe that is an aggregate of other types /// public class AggreType : FauxType { /// /// Makes the type appendable. /// /// The type. /// public static AggreType MakeTypeAppendable(IEquivalentType type) { if (type.EquivalentType == null) { type.EquivalentType = new AggreType(); } if (!(type.EquivalentType is AggreType)) { type.EquivalentType = new AggreType(type.EquivalentType); } return (AggreType) type.EquivalentType; } private readonly List Types = new List(); /// /// Initializes a new instance of the class. /// /// The types. public AggreType(params FauxType[] types) { Types.AddRange(types); } /// /// Gets the interface types. /// /// public Type[] GetInterfaceTypes() { return Types.SelectMany(it => it.GetContainedTypes()).Where(it => it.GetTypeInfo().IsInterface).ToArray(); } public override IEnumerable GetMemberNames() { return Types.SelectMany(it => it.GetMemberNames()).Distinct(); } /// /// Adds the type. /// /// The type. public void AddType(Type type) { if (!ContainsType(type)) { Types.Add(type); } } /// /// Adds the type. /// /// The type. public void AddType(FauxType type) { if (type is RealType) { foreach (var realType in type.GetContainedTypes()) { AddType(realType); } }else if (type is AggreType) { foreach (var fauxType in ((AggreType)type).Types) { AddType(fauxType); } } else { Types.Add(type); } } /// /// Gets the members. /// /// Name of the binder. /// public override IEnumerable GetMember(string binderName) { var list = new List(); foreach (FauxType t in Types) { list.AddRange(t.GetMember(binderName)); } return list; } /// /// Gets the contained types. /// /// public override Type[] GetContainedTypes() { return Types.SelectMany(it => it.GetContainedTypes()).ToArray(); } } } ================================================ FILE: Dynamitey/DynamicObjects/FluentStringLookup.cs ================================================ using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Text; using System.Reflection; namespace Dynamitey.DynamicObjects { /// /// Building block to use Method calls as dynamic lookups /// public class FluentStringLookup:DynamicObject { private readonly Func _lookup; /// /// Initializes a new instance of the class. /// /// The lookup. public FluentStringLookup(Func lookup) { _lookup = lookup; } /// /// Tries the invoke member. /// /// The binder. /// The args. /// The result. /// public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { result = _lookup(binder.Name); return true; } /// /// Tries the invoke. /// /// The binder. /// The args. /// The result. /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { result = null; if (args.Length == 1 && args.First() is String) { result = _lookup(args[0] as String); return true; } return false; } } } ================================================ FILE: Dynamitey/DynamicObjects/Get.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; namespace Dynamitey.DynamicObjects { /// /// Dynamic Proxy that exposes any properties of objects, and can massage results based on interface /// public class Get:BaseForwarder { /// /// Initializes a new instance of the class. /// /// The target. public Get(object target):base(target) { } /// /// Creates the proxy over the specified target. /// /// The target. /// public static dynamic Create(object target) { return new Get(target); } /// /// Provides the implementation for operations that get member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The result of the get operation. For example, if the method is called for a property, you can assign the property value to . /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) /// public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) { if (base.TryGetMember(binder, out result)) { return this.MassageResultBasedOnInterface(binder.Name, true, ref result); } return false; } /// /// Provides the implementation for operations that invoke a member. Classes derived from the class can override this method to specify dynamic behavior for operations such as calling a method. /// /// Provides information about the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleMethod". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The arguments that are passed to the object member during the invoke operation. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is derived from the class, is equal to 100. /// The result of the member invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) { if (!base.TryInvokeMember(binder, args, out result)) { try { //Check if there is a get property because it might return a function result = Dynamic.InvokeGet(CallTarget, binder.Name); } catch (RuntimeBinderException) { return false; } if (result == null) return false; var tDel = result as Delegate; if (!binder.CallInfo.ArgumentNames.Any() && tDel != null) { try { result = this.InvokeMethodDelegate(tDel, args); } catch (RuntimeBinderException) //If it has out parmaters etc it can't be invoked dynamically like this. //if we return false it will be handle by the GetProperty and then handled by the original dynamic invocation { return false; } } try { result = Dynamic.Invoke(result, Util.NameArgsIfNecessary(binder.CallInfo, args)); } catch (RuntimeBinderException)//If it has out parmaters etc it can't be invoked dynamically like this. //if we return false it will be handle by the GetProperty and then handled by the original dynamic invocation { return false; } } return this.MassageResultBasedOnInterface(binder.Name, true, ref result); } /// /// Tries the index of the get. /// /// The binder. /// The indexes. /// The result. /// public override bool TryGetIndex(System.Dynamic.GetIndexBinder binder, object[] indexes, out object result) { if (base.TryGetIndex(binder, indexes, out result)) { return this.MassageResultBasedOnInterface(Invocation.IndexBinderName, true, ref result); } return false; } } } ================================================ FILE: Dynamitey/DynamicObjects/LateType.cs ================================================ using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Reflection; using System.Text; using Dynamitey.Internal.Optimization; namespace Dynamitey.DynamicObjects { /// /// Late bind types from libraries not not at compile type /// public class LateType:BaseForwarder { /// /// Exception When The Late Type can not be found to bind. /// public class MissingTypeException:Exception { /// /// Initializes a new instance of the class. /// /// The typename. public MissingTypeException(string typename) : base(String.Format("Could Not Find Type. {0}", typename)) { } /// /// Initializes a new instance of the class. /// /// The message. /// The inner exception. public MissingTypeException(string message, Exception innerException) : base(message, innerException) { } } /// /// Initializes a new instance of the class. /// /// The type. public LateType(Type type) : base(type) { } private readonly string TypeName; public static Type FindType(string typeName, Assembly assembly = null) { try { if (assembly != null) { return assembly.GetType(typeName, false); } return Type.GetType(typeName, false); } catch { return null; } } /// /// Initializes a new instance of the class. /// /// Qualified Name of the type. public LateType(string typeName) : base(FindType(typeName)) { TypeName = typeName; } /// /// Initializes a new instance of the class. /// /// The assembly. /// Name of the type. public LateType(Assembly assembly, string typeName) : base(FindType(typeName, assembly)) { TypeName = typeName; } /// /// Returns a late bound constructor /// /// The late bound constructor public dynamic @new => new ConstructorForward((Type)Target); /// /// Forward argument to constructor including named arguments /// public class ConstructorForward:DynamicObject { private readonly Type _type; internal ConstructorForward(Type type) { _type = type; } /// /// Tries the invoke. /// /// The binder. /// The args. /// The result. /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { result = Dynamic.InvokeConstructor(_type, Util.NameArgsIfNecessary(binder.CallInfo, args)); return true; } } /// /// Gets a value indicating whether this Type is available at runtime. /// /// /// true if this instance is available; otherwise, false. /// public bool IsAvailable => Target != null; /// /// Gets the call target. /// /// /// The call target. /// /// protected override object CallTarget { get { if(Target ==null) throw new MissingTypeException(TypeName); return InvokeContext.CreateStatic((Type)Target); } } } } ================================================ FILE: Dynamitey/DynamicObjects/Lazy.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Dynamitey.DynamicObjects { /// /// Abstract base for the Generic class with fatory methods /// public abstract class Lazy:BaseForwarder { /// /// Creates Lazy based on the specified valuefactory. /// /// /// The value factory. /// public static dynamic Create(Func valueFactory) { return new Lazy(valueFactory); } /// /// Creates Lazy based on the specified target. /// /// /// The target. /// public static dynamic Create(System.Lazy target) { return new Lazy(target); } /// /// Initializes a new instance of the class. /// /// The target. protected Lazy(object target) : base(target) { } } /// /// Wraps a Lazy Type evalutaes on first method call /// /// public class Lazy : Lazy { /// /// Initializes a new instance of the class. /// /// The target. public Lazy(System.Lazy target) : base(target) { } /// /// Initializes a new instance of the class. /// /// The value factory. public Lazy(Func valueFactory ):base(new System.Lazy(valueFactory)) { } /// /// Returns the enumeration of all dynamic member names. /// /// /// A sequence that contains dynamic member names. /// public override IEnumerable GetDynamicMemberNames() { return ((System.Lazy)Target).IsValueCreated ? base.GetDynamicMemberNames() : Enumerable.Empty(); } /// /// Gets the call target. /// /// /// The call target. /// protected override object CallTarget => ((System.Lazy) Target).Value; } } ================================================ FILE: Dynamitey/DynamicObjects/LinqInstanceProxy.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dynamitey.DynamicObjects { /// /// Extension to Intance Proxy Configured for LINQ IEnumerable methods /// public class LinqInstanceProxy : ExtensionToInstanceProxy, IEnumerable { /// /// Initializes a new instance of the class. /// /// The target. public LinqInstanceProxy(dynamic target) :base(new InvokeContext(target, typeof(object)), typeof(IEnumerable<>), new[]{typeof(Enumerable)}, new[]{typeof(ILinq<>), typeof(IOrderedLinq<>)}) { } /// /// Creates the self. /// /// The target. /// Type of the extended. /// The static types. /// The instance hints. /// protected override ExtensionToInstanceProxy CreateSelf(object target, Type extendedType, Type[] staticTypes, Type[] instanceHints) { return new LinqInstanceProxy(target); } /// /// Gets the enumerator. /// /// public IEnumerator GetEnumerator() { return ((dynamic) CallTarget).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } #pragma warning disable 1591 // ReSharper disable UnusedMember.Global public interface ILinq : IEnumerable { TSource Aggregate(Func func); TAccumulate Aggregate(TAccumulate seed, Func func); TResult Aggregate(TAccumulate seed, Func func, Func resultSelector); Boolean All(Func predicate); Boolean Any(); Boolean Any(Func predicate); ILinq AsEnumerable(); Double Average(Func selector); Nullable Average(Func> selector); Double Average(Func selector); Nullable Average(Func> selector); Single Average(Func selector); Nullable Average(Func> selector); Double Average(Func selector); Nullable Average(Func> selector); Decimal Average(Func selector); Nullable Average(Func> selector); ILinq Cast(); ILinq Concat(IEnumerable second); Boolean Contains(TSource value); Boolean Contains(TSource value, IEqualityComparer comparer); Int32 Count(); Int32 Count(Func predicate); ILinq DefaultIfEmpty(); ILinq DefaultIfEmpty(TSource defaultValue); ILinq Distinct(); ILinq Distinct(IEqualityComparer comparer); TSource ElementAt(Int32 index); TSource ElementAtOrDefault(Int32 index); ILinq Except(IEnumerable second); ILinq Except(IEnumerable second, IEqualityComparer comparer); TSource First(); TSource First(Func predicate); TSource FirstOrDefault(); TSource FirstOrDefault(Func predicate); ILinq> GroupBy(Func keySelector); ILinq> GroupBy(Func keySelector, IEqualityComparer comparer); ILinq> GroupBy(Func keySelector, Func elementSelector); ILinq> GroupBy(Func keySelector, Func elementSelector, IEqualityComparer comparer); ILinq GroupBy(Func keySelector, Func, TResult> resultSelector); ILinq GroupBy(Func keySelector, Func elementSelector, Func, TResult> resultSelector); ILinq GroupBy(Func keySelector, Func, TResult> resultSelector, IEqualityComparer comparer); ILinq GroupBy(Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer); ILinq GroupJoin(IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector); ILinq GroupJoin(IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer comparer); ILinq Intersect(IEnumerable second); ILinq Intersect(IEnumerable second, IEqualityComparer comparer); ILinq Join(IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector); ILinq Join(IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer comparer); TSource Last(); TSource Last(Func predicate); TSource LastOrDefault(); TSource LastOrDefault(Func predicate); Int64 LongCount(); Int64 LongCount(Func predicate); TSource Max(); Int32 Max(Func selector); Nullable Max(Func> selector); Int64 Max(Func selector); Nullable Max(Func> selector); Single Max(Func selector); Nullable Max(Func> selector); Double Max(Func selector); Nullable Max(Func> selector); Decimal Max(Func selector); Nullable Max(Func> selector); TResult Max(Func selector); TSource Min(); Int32 Min(Func selector); Nullable Min(Func> selector); Int64 Min(Func selector); Nullable Min(Func> selector); Single Min(Func selector); Nullable Min(Func> selector); Double Min(Func selector); Nullable Min(Func> selector); Decimal Min(Func selector); Nullable Min(Func> selector); TResult Min(Func selector); ILinq OfType(); IOrderedLinq OrderBy(Func keySelector); IOrderedLinq OrderBy(Func keySelector, IComparer comparer); IOrderedLinq OrderByDescending(Func keySelector); IOrderedLinq OrderByDescending(Func keySelector, IComparer comparer); ILinq Reverse(); ILinq Select(Func selector); ILinq Select(Func selector); ILinq SelectMany(Func> selector); ILinq SelectMany(Func> selector); ILinq SelectMany(Func> collectionSelector, Func resultSelector); ILinq SelectMany(Func> collectionSelector, Func resultSelector); Boolean SequenceEqual(IEnumerable second); Boolean SequenceEqual(IEnumerable second, IEqualityComparer comparer); TSource Single(); TSource Single(Func predicate); TSource SingleOrDefault(); TSource SingleOrDefault(Func predicate); ILinq Skip(Int32 count); ILinq SkipWhile(Func predicate); ILinq SkipWhile(Func predicate); Int32 Sum(Func selector); Nullable Sum(Func> selector); Int64 Sum(Func selector); Nullable Sum(Func> selector); Single Sum(Func selector); Nullable Sum(Func> selector); Double Sum(Func selector); Nullable Sum(Func> selector); Decimal Sum(Func selector); Nullable Sum(Func> selector); ILinq Take(Int32 count); ILinq TakeWhile(Func predicate); ILinq TakeWhile(Func predicate); TSource[] ToArray(); Dictionary ToDictionary(Func keySelector); Dictionary ToDictionary(Func keySelector, IEqualityComparer comparer); Dictionary ToDictionary(Func keySelector, Func elementSelector); Dictionary ToDictionary(Func keySelector, Func elementSelector, IEqualityComparer comparer); List ToList(); ILookup ToLookup(Func keySelector); ILookup ToLookup(Func keySelector, IEqualityComparer comparer); ILookup ToLookup(Func keySelector, Func elementSelector); ILookup ToLookup(Func keySelector, Func elementSelector, IEqualityComparer comparer); ILinq Union(IEnumerable second); ILinq Union(IEnumerable second, IEqualityComparer comparer); ILinq Where(Func predicate); ILinq Where(Func predicate); ILinq Zip(IEnumerable second, Func resultSelector); } public interface IOrderedLinq : ILinq, IOrderedEnumerable { IOrderedLinq ThenBy(Func keySelector); IOrderedLinq ThenBy(Func keySelector, IComparer comparer); IOrderedLinq ThenByDescending(Func keySelector); IOrderedLinq ThenByDescending(Func keySelector, IComparer comparer); } // ReSharper restore UnusedMember.Global #pragma warning restore 1591 } ================================================ FILE: Dynamitey/DynamicObjects/List.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using Microsoft.CSharp.RuntimeBinder; namespace Dynamitey.DynamicObjects { /// /// Expando-Type List for dynamic objects /// public class List : BaseDictionary, IList, IDictionary, INotifyCollectionChanged, IList { /// /// Wrapped list /// protected IList _list; private static readonly object ListLock = new object(); /// /// Initializes a new instance of the class. /// /// The contents. /// The members. public List( IEnumerable contents =null, IEnumerable> members =null):base(members) { if (contents == null) { _list = new List(); return; } if (contents is IList) { _list = contents as IList; } else { _list = contents.ToList(); } } IEnumerator> IEnumerable>.GetEnumerator() { return _dictionary.GetEnumerator(); } /// /// Gets the enumerator. /// /// public IEnumerator GetEnumerator() { return _list.GetEnumerator(); } /// /// Adds the specified item. /// /// The item. public void Add(dynamic item) { InsertHelper(item); } /// /// Clears this instance. /// public void Clear() { lock (ListLock) { _list.Clear(); } OnCollectionChanged(NotifyCollectionChangedAction.Reset); } /// /// Determines whether [contains] [the specified item]. /// /// The item. /// /// true if [contains] [the specified item]; otherwise, false. /// public bool Contains(dynamic item) { return _list.Contains(item); } /// /// Copies to. /// /// The array. /// Index of the array. public void CopyTo(object[] array, int arrayIndex) { _list.CopyTo(array, arrayIndex); } /// /// Gets the count. /// /// The count. public int Count => _list.Count; /// /// Indexes the of. /// /// The item. /// public int IndexOf(dynamic item) { lock (ListLock) { return _list.IndexOf(item); } } /// /// Inserts the specified index. /// /// The index. /// The item. public void Insert(int index, dynamic item) { InsertHelper(item,index); } private void InsertHelper(object item, int? index = null) { lock (ListLock) { if (!index.HasValue) { index = _list.Count; _list.Add(item); } else { _list.Insert(index.Value, item); } } OnCollectionChanged(NotifyCollectionChangedAction.Add, newItem: item, newIndex: index); } /// /// Removes at. /// /// The index. public void RemoveAt(int index) { RemoveHelper(index: index); } /// /// Removes the specified item. /// /// The item. /// public bool Remove(dynamic item) { return RemoveHelper(item); } private bool RemoveHelper(object item = null, int? index = null) { lock (ListLock) { if (item != null) { index = _list.IndexOf(item); if (index < 0) return false; } item = item ?? _list[index.GetValueOrDefault()]; _list.RemoveAt(index.GetValueOrDefault()); } OnCollectionChanged(NotifyCollectionChangedAction.Remove, oldItem: item, oldIndex: index); return true; } /// /// Gets or sets the at the specified index. /// /// /// The . /// /// The index. /// public dynamic this[int index] { get => _list[index]; set { object tOld; lock (ListLock) { tOld = _list[index]; _list[index] = value; } OnCollectionChanged(NotifyCollectionChangedAction.Replace, tOld, value, index); } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Called when [collection changed]. /// /// The action. /// The old item. /// The new item. /// The old index. /// The new index. protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem = null, object newItem = null, int? oldIndex = null, int? newIndex = null) { if (CollectionChanged != null) { switch (action) { case NotifyCollectionChangedAction.Add: CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItem, newIndex.GetValueOrDefault())); break; case NotifyCollectionChangedAction.Remove: CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, oldItem, oldIndex.GetValueOrDefault())); break; case NotifyCollectionChangedAction.Replace: CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, oldItem, newItem, oldIndex.GetValueOrDefault())); break; case NotifyCollectionChangedAction.Reset: CollectionChanged(this,new NotifyCollectionChangedEventArgs(action)); break; } } switch (action) { case NotifyCollectionChangedAction.Add: OnPropertyChanged("Count"); break; case NotifyCollectionChangedAction.Remove: OnPropertyChanged("Count"); break; case NotifyCollectionChangedAction.Replace: break; case NotifyCollectionChangedAction.Reset: OnPropertyChanged("Count"); break; } } /// /// Occurs when the collection changes. /// public event NotifyCollectionChangedEventHandler CollectionChanged; dynamic IDictionary.this[string key] { get => _dictionary[key]; set => SetProperty(key, value); } /// /// Equalses the specified other. /// /// The other. /// public bool Equals(List other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return base.Equals(other) && Equals(other._list, _list); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; return Equals(obj as List); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { unchecked { return (base.GetHashCode()*397) ^ _list.GetHashCode(); } } /// /// Gets or sets the override getting item method names. USED for GetItemProperties /// /// The override getting item method names. public Func, IEnumerable> OverrideGettingItemMethodNames { get; set; } /// /// Gets the represented item. USED fOR GetItemProperties /// /// protected virtual dynamic GetRepresentedItem() { var tItem = ((IEnumerable)this).FirstOrDefault(); return tItem; } #region Implementation of ICollection /// /// Copies to. /// /// The array. /// The index. public void CopyTo(Array array, int index) { ((IList)_list).CopyTo(array, index); } private readonly object _syncRoot = new object(); /// /// Gets the sync root. /// /// /// The sync root. /// public object SyncRoot => _syncRoot; /// /// Gets a value indicating whether this instance is synchronized. /// /// /// true if this instance is synchronized; otherwise, false. /// public bool IsSynchronized => false; #endregion #region Implementation of IList int IList.Add(object value) { Add(value); return Count - 1; } void IList.Remove(object value) { Remove(value); } /// /// Gets a value indicating whether this instance is fixed size. /// /// /// true if this instance is fixed size; otherwise, false. /// public bool IsFixedSize => false; #endregion } } ================================================ FILE: Dynamitey/DynamicObjects/Mimic.cs ================================================ using System.Dynamic; using System; using System.Reflection; namespace Dynamitey.DynamicObjects { /// /// Class for TDD, used for mocking any dynamic object /// public class Mimic : DynamicObject { /// /// Override on DynamicObject /// /// /// /// /// public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) { result = new Mimic(); return true; } /// /// Override on DynamicObject /// /// /// /// public override bool TryConvert(ConvertBinder binder, out object result) { result = Dynamic.InvokeConstructor(binder.ReturnType); return true; } /// /// Override on DynamicObject /// /// /// /// /// public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result) { result = new Mimic(); return true; } /// /// Override on DynamicObject /// /// /// /// public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes) { return true; } /// /// Override on DynamicObject /// /// /// public override bool TryDeleteMember(DeleteMemberBinder binder) { return true; } /// /// Override on DynamicObject /// /// /// /// /// public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { result = new Mimic(); return true; } /// /// Override on DynamicObject /// /// /// /// public override bool TryGetMember(GetMemberBinder binder, out object result) { result = new Mimic(); return true; } /// /// Override on DynamicObject /// /// /// /// /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { result = new Mimic(); return true; } /// /// Override on DynamicObject /// /// /// /// /// public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { result = new Mimic(); return true; } /// /// Override on DynamicObject /// /// /// /// /// public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { return true; } /// /// Override on DynamicObject /// /// /// /// public override bool TrySetMember(SetMemberBinder binder, object value) { return true; } /// /// Override on DynamicObject /// /// /// /// public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) { result = new Mimic(); return true; } } } ================================================ FILE: Dynamitey/DynamicObjects/Recorder.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Text; using Dynamitey.Internal.Optimization; namespace Dynamitey.DynamicObjects { /// /// Proxy that Records Dynamic Invocations on an object /// public class Recorder:BaseForwarder { /// /// Initializes a new instance of the class. /// public Recorder():base(new Dummy()) { Recording = new List(); } /// /// Gets or sets the recording. /// /// The recording. public IList Recording { get; protected set; } /// /// Initializes a new instance of the class. /// /// The target. public Recorder(object target) : base(target) { Recording = new List(); } /// /// Replays the recording on target. /// /// The target. public T ReplayOn(T target) { foreach (var tInvocation in Recording) { tInvocation.InvokeWithStoredArgs(target); } return target; } /// /// Provides the implementation for operations that get member values. Classes derived from the class can override this method to specify dynamic behavior for operations such as getting a value for a property. /// /// Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The result of the get operation. For example, if the method is called for a property, you can assign the property value to . /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) /// public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) { if (base.TryGetMember(binder, out result)) { Recording.Add(new Invocation(InvocationKind.Get,binder.Name)); return true; } return false; } /// /// Tries the set member. /// /// The binder. /// The value. /// public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value) { if (base.TrySetMember(binder, value)) { Recording.Add(new Invocation(InvocationKind.Set,binder.Name,value)); return true; } return false; } /// /// Tries the invoke member. /// /// The binder. /// The args. /// The result. /// public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) { if (base.TryInvokeMember(binder, args, out result)) { Recording.Add(new Invocation(InvocationKind.InvokeMemberUnknown, binder.Name, Util.NameArgsIfNecessary(binder.CallInfo, args))); return true; } return false; } /// /// Tries the index of the get. /// /// The binder. /// The indexes. /// The result. /// public override bool TryGetIndex(System.Dynamic.GetIndexBinder binder, object[] indexes, out object result) { if (base.TryGetIndex(binder, indexes, out result)) { Recording.Add(new Invocation(InvocationKind.GetIndex, Invocation.IndexBinderName, Util.NameArgsIfNecessary(binder.CallInfo, indexes))); return true; } return false; } /// /// Tries the index of the set. /// /// The binder. /// The indexes. /// The value. /// public override bool TrySetIndex(System.Dynamic.SetIndexBinder binder, object[] indexes, object value) { if (base.TrySetIndex(binder, indexes, value)) { var tCombinedArgs = indexes.Concat(new[] { value }).ToArray(); Recording.Add(new Invocation(InvocationKind.GetIndex, Invocation.IndexBinderName, Util.NameArgsIfNecessary(binder.CallInfo, tCombinedArgs))); return true; } return false; } } } ================================================ FILE: Dynamitey/DynamicObjects/RegexMatch.cs ================================================ using System; using System.Dynamic; using System.Linq; using System.Text.RegularExpressions; using System.Collections.Generic; using System.Reflection; using Dynamitey.Internal.Compat; namespace Dynamitey.DynamicObjects { /// /// A Regex Match Interface /// public interface IRegexMatch { /// /// Gets the value. /// /// /// The value. /// string Value { get;} } /// /// A Dynamic Regex Match /// public class RegexMatch : BaseObject, IRegexMatch { private readonly Match _match; private readonly Regex _regex; /// /// Initializes a new instance of the class. /// /// The match. /// The regex. public RegexMatch(Match match, Regex regex = null) { _match = match; _regex = regex; } /// /// Gets the dynamic member names. /// /// public override IEnumerable GetDynamicMemberNames() { if (_regex == null) return Enumerable.Empty(); return _regex.GetGroupNames(); } /// /// Tries the get member. /// /// The binder. /// The result. /// public override bool TryGetMember(GetMemberBinder binder, out object result) { var tGroup = _match.Groups[binder.Name]; if (!TryTypeForName(binder.Name, out var outType)) outType = typeof (string); if (!tGroup.Success) { result = null; if (outType.GetTypeInfo().IsValueType) result = Dynamic.InvokeConstructor(outType); return true; } result = Dynamic.CoerceConvert(tGroup.Value, outType); return true; } /// /// Gets the with the specified value. /// /// /// The . /// /// The value. /// public string this[int value] { get { var tGroup = _match.Groups[value]; if (!tGroup.Success) { return null; } return tGroup.Value; } } /// /// Gets the with the specified value. /// /// /// The . /// /// The value. /// public string this[string value] { get { var tGroup = _match.Groups[value]; if (!tGroup.Success) { return null; } return tGroup.Value; } } string IRegexMatch.Value => _match.Value; /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return _match.ToString(); } } } ================================================ FILE: Dynamitey/Dynamitey.csproj ================================================  netstandard2.0;net40 (pronounced dyna-mighty) flexes DLR muscle to do meta-mazing things in .net Ekon Benefits Copyright 2017 Ekon Benefits https://github.com/ekonbenefits/dynamitey Apache-2.0 dynamic metaprogramming dlr reflection currying tuples expando latetypes True True True True True sn.snk False TextTemplatingFileGenerator InlineLambdas.cs TextTemplatingFileGenerator InvokeHelper.cs TextTemplatingFileGenerator ThisFunctions.cs True True InlineLambdas.tt True True InvokeHelper.tt True True ThisFunctions.tt ================================================ FILE: Dynamitey/Expando.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System.Dynamic; using Dynamitey.DynamicObjects; namespace Dynamitey { public class Expando : Builder { // ReSharper disable StaticFieldInGenericType private static readonly dynamic _expandoBuilder = new Builder().Object; // ReSharper restore StaticFieldInGenericType /// /// Initializes a new instance of the class. /// This constructor is shorthand for new Builder<ExpandoObject>(); /// public Expando() { } /// /// Gets the new expandoObject builder. This method is short hand for Build>ExpandoObject>.NewObject() /// /// The new expandoObject. public static dynamic New => _expandoBuilder; } } ================================================ FILE: Dynamitey/FluentRegex.cs ================================================ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Dynamitey { /// /// Extension Methods for fluent Regex /// public static class FluentRegex { /// /// Fluents the filter. /// /// The list. /// The regex. /// public static IEnumerable FluentFilter(this IEnumerable list, Regex regex) { return list.Select(it => regex.Match(it)).Where(it => it.Success).Select(it => new DynamicObjects.RegexMatch(it, regex)).Cast(); } /// /// Matches the specified input string. /// /// The input string. /// The regex. /// public static IEnumerable Matches(string inputString, Regex regex) { var tMatches = regex.Matches(inputString); return tMatches.Cast().Where(it => it.Success).Select(it => new DynamicObjects.RegexMatch(it, regex)).Cast(); } /// /// Matches the specified input string. /// /// The input string. /// The regex. /// public static dynamic Match(string inputString, Regex regex) { var tMatch = regex.Match(inputString); return tMatch.Success ? new DynamicObjects.RegexMatch(tMatch, regex) : null; } /// /// Fluents the match. /// /// The regex. /// The input string. /// public static dynamic FluentMatch(this Regex regex, string inputString) { var tMatch = regex.Match(inputString); return tMatch.Success ? new DynamicObjects.RegexMatch(tMatch, regex) : null; } /// /// Fluents the matches. /// /// The regex. /// The input string. /// public static IEnumerable FluentMatches(this Regex regex, string inputString) { return Matches(inputString, regex); } } } ================================================ FILE: Dynamitey/InlineLambdas.cs ================================================ // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Linq; namespace Dynamitey { /// /// Fluent Class for writing inline lambdass /// /// The type of the R. public static class Return { /// /// Arguments /// /// The lambda. /// The lambda. public static Func Arguments(Func del) { return del; } /// /// This and arguments. /// /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The type of the Argument 16. /// The lambdas. /// public static Func Arguments(Func del) { return del; } /// /// this and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The type of the Argument 16. /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } } /// /// Fluent class for writing inline lambdas that return void /// public static class ReturnVoid { /// /// Arguments /// /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and arguments. /// /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } /// /// Arguments /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The type of the Argument 16. /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and Arguments. /// /// The type of the Argument 1. /// The type of the Argument 2. /// The type of the Argument 3. /// The type of the Argument 4. /// The type of the Argument 5. /// The type of the Argument 6. /// The type of the Argument 7. /// The type of the Argument 8. /// The type of the Argument 9. /// The type of the Argument 10. /// The type of the Argument 11. /// The type of the Argument 12. /// The type of the Argument 13. /// The type of the Argument 14. /// The type of the Argument 15. /// The type of the Argument 16. /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } } } ================================================ FILE: Dynamitey/InlineLambdas.tt ================================================ <#@ template language="C#" #> <#@ output extension="cs" #> // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Linq; namespace Dynamitey { /// /// Fluent Class for writing inline lambdass /// /// The type of the R. public static class Return { /// /// Arguments /// /// The lambda. /// The lambda. public static Func Arguments(Func del) { return del; } /// /// This and arguments. /// /// The del. /// public static ThisFunc ThisAndArguments(ThisFunc del) { return del; } <#for(int i=1; i<=16;i++){ #> <# var tFuncTArgs ="T1"; for(int j=2;j<=i;j++){ tFuncTArgs +=String.Format(",T{0}",j); } #> /// /// Arguments /// <# for(int j=1;j<=i;j++){ #> /// The type of the Argument <#=j#>. <# } #> /// The lambdas. /// public static Func<<#=tFuncTArgs#>,TR> Arguments<<# Write(tFuncTArgs); #>>(Func<<#=tFuncTArgs#>,TR> del) { return del; } /// /// this and Arguments. /// <# for(int j=1;j<=i;j++){ #> /// The type of the Argument <#=j#>. <# } #> /// The del. /// public static ThisFunc> ThisAndArguments<<# Write(tFuncTArgs); #>>(ThisFunc> del) { return del; } <# } #> } /// /// Fluent class for writing inline lambdas that return void /// public static class ReturnVoid { /// /// Arguments /// /// The lambda. /// The lambda. public static Action Arguments(Action del) { return del; } /// /// This and arguments. /// /// The del. /// public static ThisAction ThisAndArguments(ThisAction del) { return del; } <#for(int i=1; i<=16;i++){ #> <# var tFuncTArgs ="T1"; for(int j=2;j<=i;j++){ tFuncTArgs +=String.Format(",T{0}",j); } #> /// /// Arguments /// <# for(int j=1;j<=i;j++){ #> /// The type of the Argument <#=j#>. <# } #> /// The lambda. /// The lambda. public static Action<<#=tFuncTArgs#>> Arguments<<#=tFuncTArgs#>>(Action<<#=tFuncTArgs#>> del) { return del; } /// /// This and Arguments. /// <# for(int j=1;j<=i;j++){ #> /// The type of the Argument <#=j#>. <# } #> /// The del. /// public static ThisAction<<#=tFuncTArgs#>> ThisAndArguments<<#=tFuncTArgs#>>(ThisAction<<#=tFuncTArgs#>> del) { return del; } <# } #> } } ================================================ FILE: Dynamitey/Internal/Compat/Net40.cs ================================================  namespace Dynamitey.Internal.Compat { using System; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Globalization; using System.Threading; public static class Net40 { #if NETFRAMEWORK || PROFILE158 public static Type GetTypeInfo(this Type type) { return type; } public static MethodInfo GetMethodInfo(this Delegate del) { return del.Method; } public static CultureInfo GetDefaultThreadCurrentCulture() { return Thread.CurrentThread.CurrentCulture; } #else public static CultureInfo GetDefaultThreadCurrentCulture() { return CultureInfo.DefaultThreadCurrentCulture; } #endif } } ================================================ FILE: Dynamitey/Internal/Curry.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using Dynamitey.Internal.Optimization; using System.Reflection; namespace Dynamitey.Internal { /// /// Internal Implementation of /// public class Curry : DynamicObject, IPartialApply { /// /// Pipe argument (left side) into curried function (right side) /// /// The argument. /// The function. /// public static dynamic operator |(dynamic argument, Curry function) { return ((dynamic)function)(argument); } private readonly object _target; private readonly int? _totalArgCount; internal Curry(object target, int? totalArgCount=null) { _target = target; _totalArgCount = totalArgCount; } /// /// Provides implementation for binary operations. Classes derived from the class can override this method to specify dynamic behavior for operations such as addition and multiplication. /// /// Provides information about the binary operation. The binder.Operation property returns an object. For example, for the sum = first + second statement, where first and second are derived from the DynamicObject class, binder.Operation returns ExpressionType.Add. /// The right operand for the binary operation. For example, for the sum = first + second statement, where first and second are derived from the DynamicObject class, is equal to second. /// The result of the binary operation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) { result = null; if (binder.Operation == ExpressionType.LeftShift) { result =((dynamic)(this))(arg); return true; } return false; } /// /// Provides implementation for type conversion operations. Classes derived from the class can override this method to specify dynamic behavior for operations that convert an object from one type to another. /// /// Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted. For example, for the statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic), where sampleObject is an instance of the class derived from the class, binder.Type returns the type. The binder.Explicit property provides information about the kind of conversion that occurs. It returns true for explicit conversion and false for implicit conversion. /// The result of the type conversion operation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryConvert(ConvertBinder binder, out object result) { result = Dynamic.CoerceToDelegate(this, binder.Type); return result != null; } #if SILVERLIGHT5 /// /// Gets the custom Type. /// /// public Type GetCustomType() { return this.GetDynamicCustomType(); } #endif /// /// Provides the implementation for operations that invoke a member. Classes derived from the class can override this method to specify dynamic behavior for operations such as calling a method. /// /// Provides information about the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is an instance of the class derived from the class, binder.Name returns "SampleMethod". The binder.IgnoreCase property specifies whether the member name is case-sensitive. /// The arguments that are passed to the object member during the invoke operation. For example, for the statement sampleObject.SampleMethod(100), where sampleObject is derived from the class, [0] is equal to 100. /// The result of the member invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { result = new PartialApply(_target, Util.NameArgsIfNecessary(binder.CallInfo, args), binder.Name, _totalArgCount); return true; } /// /// Provides the implementation for operations that invoke an object. Classes derived from the class can override this method to specify dynamic behavior for operations such as invoking an object or a delegate. /// /// Provides information about the invoke operation. /// The arguments that are passed to the object during the invoke operation. For example, for the sampleObject(100) operation, where sampleObject is derived from the class, [0] is equal to 100. /// The result of the object invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown. /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { var tCurrying = _target as PartialApply; var curryResult = tCurrying != null //If already currying append ? new PartialApply(tCurrying.Target, tCurrying.Args.Concat(Util.NameArgsIfNecessary(binder.CallInfo, args)). ToArray(), tCurrying.MemberName, tCurrying.TotalArgCount, tCurrying.InvocationKind) : new PartialApply(_target, Util.NameArgsIfNecessary(binder.CallInfo, args), String.Empty, _totalArgCount); result = curryResult; if (args.Length == curryResult.TotalArgCount) result= ((dynamic) curryResult)(); return true; } } } ================================================ FILE: Dynamitey/Internal/InvokeSetters.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq; using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; using Dynamitey.Internal.Compat; using System.Reflection; namespace Dynamitey.Internal { /// /// Internal class implmenation for /// public class InvokeSetters : DynamicObject { internal InvokeSetters() { } /// /// Provides the implementation for operations that invoke an object. Classes derived from the class can override this method to specify dynamic behavior for operations such as invoking an object or a delegate. /// /// Provides information about the invoke operation. /// The arguments that are passed to the object during the invoke operation. For example, for the sampleObject(100) operation, where sampleObject is derived from the class, [0] is equal to 100. /// The result of the object invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown. /// public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { IEnumerable> tDict = null; object target = null; result = null; //Setup Properties as dictionary if (binder.CallInfo.ArgumentNames.Any()) { if (binder.CallInfo.ArgumentNames.Count + 1 == binder.CallInfo.ArgumentCount) { target = args.First(); tDict = binder.CallInfo.ArgumentNames .Zip(args.Skip(1), (key, value) => new { key, value }) .ToDictionary(k => k.key, v => v.value); }else { throw new RuntimeBinderException("InvokeSetAll requires first parameter to be target unamed, and all other parameters to be named."); } } else if (args.Length == 2) { target = args[0]; if (args[1] is IEnumerable>) { tDict = (IEnumerable>)args[1]; } else if (args[1] is IEnumerable && args[1].GetType().GetTypeInfo().IsGenericType ) { var tEnumerableArg = (IEnumerable)args[1]; var tInterface = tEnumerableArg.GetType().GetTypeInfo().GetInterfaces().FirstOrDefault(it=>it.Name =="IEnumerable`1"); if(tInterface !=null) { var tParamTypes = tInterface.GetTypeInfo().GetGenericArguments(); if(tParamTypes.Length ==1 && tParamTypes[0].GetGenericTypeDefinition() == typeof(Tuple<,>)) { tDict= tEnumerableArg.Cast().ToDictionary(k => (string) k.Item1, v => (object) v.Item2); } } } else if (Util.IsAnonymousType(args[1])) { var keyDict = new Dictionary(); foreach (var tProp in args[1].GetType().GetTypeInfo().GetProperties()) { keyDict[tProp.Name] = Dynamic.InvokeGet(args[1], tProp.Name); } tDict = keyDict; } } //Invoke all properties if (target != null && tDict != null) { foreach (var tPair in tDict) { Dynamic.InvokeSetChain(target, tPair.Key, tPair.Value); } result = target; return true; } return false; } } } ================================================ FILE: Dynamitey/Internal/Optimization/BareBonesList.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections; using System.Collections.Generic; namespace Dynamitey.Internal.Optimization { internal class BareBonesList: ICollection { private T[] _list; private int _addIndex; private int _length; /// /// Initializes a new instance of the class. /// /// The max length that the list cannot grow beyound public BareBonesList(int length) { _list = new T[length]; _length = length; } public void Add(T item) { _list[_addIndex++] = item; } public void Clear() { throw new NotSupportedException(); } public bool Contains(T item) { throw new NotSupportedException(); } public void CopyTo(T[] array, int arrayIndex) { Array.Copy(_list,arrayIndex,array,0,_length); } public bool Remove(T item) { throw new NotSupportedException(); } public int Count => _length; public bool IsReadOnly => false; /// /// Gets the enumerator. with bare bones this is good only once /// /// public IEnumerator GetEnumerator() { return new BareBonesEnumerator(_list,_addIndex); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } internal class BareBonesEnumerator : IEnumerator { private T[] _list; private int _enumerateInex = -1; private int _length; public BareBonesEnumerator(T[] list, int length) { _list = list; _length = length; } public void Dispose() { } public bool MoveNext() { _enumerateInex++; return _enumerateInex < _length; } public void Reset() { _enumerateInex = 0; } public T Current => _list[_enumerateInex]; object IEnumerator.Current => Current; } } } ================================================ FILE: Dynamitey/Internal/Optimization/BinderHash.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dynamitey.Internal.Optimization { internal class BinderHash { protected BinderHash(Type delegateType, String name, Type context, string[] argNames, Type binderType, bool staticContext, bool isEvent, bool knownBinder) { KnownBinder = knownBinder; BinderType = binderType; StaticContext = staticContext; DelegateType = delegateType; Name = name; IsSpecialName = false; GenericArgs = null; Context = context; ArgNames = argNames; IsEvent = isEvent; } protected BinderHash(Type delegateType, InvokeMemberName name, Type context, string[] argNames, Type binderType, bool staticContext, bool isEvent, bool knownBinder) { KnownBinder = knownBinder; BinderType = binderType; StaticContext = staticContext; DelegateType = delegateType; Name = name.Name; IsSpecialName = name.IsSpecialName; GenericArgs = name.GenericArgs; Context = context; ArgNames = argNames; IsEvent = isEvent; } public bool KnownBinder { get; } public Type BinderType { get; } public bool StaticContext { get; } public bool IsEvent { get; } public Type DelegateType { get; } public string Name { get; } public bool IsSpecialName { get; } public Type[] GenericArgs { get; } public Type Context { get; } public string[] ArgNames { get; } public virtual bool Equals(BinderHash other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; var tArgNames = ArgNames; var tOtherArgNames = other.ArgNames; var tGenArgs = GenericArgs; var tOtherGenArgs = other.GenericArgs; return !(tOtherArgNames == null && tArgNames != null) && !(tArgNames == null && tOtherArgNames != null) && other.IsEvent == IsEvent && other.StaticContext == StaticContext && other.Context == Context && (KnownBinder || other.BinderType == BinderType) && other.DelegateType == DelegateType && Equals(other.Name, Name) && !(other.IsSpecialName ^ IsSpecialName) && !(tOtherGenArgs == null && tGenArgs != null) && !(tGenArgs == null && tOtherGenArgs != null) && (tOtherGenArgs == null || tOtherGenArgs.SequenceEqual(tGenArgs)) && (tOtherArgNames == null || tOtherArgNames.SequenceEqual(tArgNames)); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (!(obj is BinderHash)) return false; return Equals((BinderHash) obj); } public override int GetHashCode() { unchecked { var tArgNames = ArgNames; int result = (tArgNames == null ? 0 : tArgNames.Length * 397); result = (result ^ StaticContext.GetHashCode()); //result = (result * 397) ^ DelegateType.GetHashCode(); //result = (result * 397) ^ Context.GetHashCode(); result = (result * 397) ^ Name.GetHashCode(); return result; } } } internal class BinderHash : BinderHash where T : class { public static BinderHash Create(string name, Type context, string[] argNames, Type binderType, bool staticContext, bool isEvent, bool knownBinder) { return new BinderHash(name, context, argNames, binderType, staticContext, isEvent, knownBinder); } public static BinderHash Create(InvokeMemberName name, Type context, string[] argNames, Type binderType, bool staticContext, bool isEvent, bool knownBinder) { return new BinderHash(name, context, argNames, binderType, staticContext, isEvent, knownBinder); } protected BinderHash(InvokeMemberName name, Type context, string[] argNames, Type binderType, bool staticContext, bool isEvent,bool knownBinder) : base(typeof(T), name, context, argNames, binderType, staticContext, isEvent,knownBinder) { } protected BinderHash(string name, Type context, string[] argNames, Type binderType, bool staticContext, bool isEvent, bool knownBinder) : base(typeof(T), name, context, argNames, binderType, staticContext, isEvent, knownBinder) { } public override bool Equals(BinderHash other) { if (other is BinderHash) { var tGenArgs = GenericArgs; var tOtherGenArgs = other.GenericArgs; var tArgNames = ArgNames; var tOtherArgNames = other.ArgNames; return !(tOtherArgNames == null && tArgNames != null) && !(tArgNames == null && tOtherArgNames != null) && other.IsEvent == IsEvent && other.StaticContext == StaticContext && (KnownBinder || other.BinderType == BinderType) && other.Context == Context && Equals(other.Name, Name) && !(other.IsSpecialName ^ IsSpecialName) && !(tOtherGenArgs == null && tGenArgs != null) && !(tGenArgs == null && tOtherGenArgs != null) && (tGenArgs == null || tGenArgs.SequenceEqual(tOtherGenArgs)) && (ArgNames == null || other.ArgNames.SequenceEqual(ArgNames)); } return false; } } } ================================================ FILE: Dynamitey/Internal/Optimization/InvokeHelper-Regular.cs ================================================ using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using Dynamitey.DynamicObjects; using Microsoft.CSharp.RuntimeBinder; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; using Dynamitey.Internal.Compat; namespace Dynamitey.Internal.Optimization { internal class DummmyNull { } internal static partial class InvokeHelper { internal const int Unknown =0; internal const int KnownGet = 1; internal const int KnownSet = 2; internal const int KnownMember = 3; internal const int KnownDirect = 4; internal const int KnownConstructor = 5; private static readonly object _clearDynamicLock = new object(); internal static IDictionary> DynamicInvokeCreateCallSite { get { lock (_clearDynamicLock) { return _dynamicInvokeCreateCallSite ?? (_dynamicInvokeCreateCallSite = new Dictionary>()); } } } internal static void ClearFullyDynamicCache() { lock (_clearDynamicLock) { _dynamicInvokeCreateCallSite = null; } } private static bool TryDynamicCachedCallSite(BinderHash hash, int knownBinderType, out CallSite callSite) where T: class { switch(knownBinderType) { default: return BinderCache.Cache.TryGetValue(hash, out callSite); case KnownGet: return BinderGetCache.Cache.TryGetValue(hash, out callSite); case KnownSet: return BinderSetCache.Cache.TryGetValue(hash, out callSite); case KnownMember: return BinderMemberCache.Cache.TryGetValue(hash, out callSite); case KnownDirect: return BinderDirectCache.Cache.TryGetValue(hash, out callSite); case KnownConstructor: return BinderConstructorCache.Cache.TryGetValue(hash, out callSite); } } internal static readonly dynamic BuildProxy = new DynamicObjects.LateType( "ImpromptuInterface.Build.BuildProxy, ImpromptuInterface, PublicKeyToken=0b1781c923b2975b"); internal static Type EmitCallSiteFuncType(IEnumerable argTypes, Type returnType) { try { //Impromptu Interface version 8.04 return BuildProxy.DefaultProxyMaker.EmitCallSiteFuncType(argTypes, returnType); } catch (LateType.MissingTypeException ex) { try { //Impromptu Interface 7.X return BuildProxy.EmitCallSiteFuncType(argTypes, returnType); } catch (LateType.MissingTypeException) { throw new TypeLoadException("Cannot Emit long delegates without ImpromptuInterface installed", ex); } } } internal static HashSet _allCaches = new HashSet(); private static readonly object _binderCacheLock = new object(); private static readonly object _callSiteCacheLock = new object(); internal static IDictionary> _dynamicInvokeCreateCallSite; internal static void ClearAllCaches() { lock (_binderCacheLock) { foreach (Action instance in _allCaches) { instance(); } } lock (_callSiteCacheLock) { ClearFullyDynamicCache(); } } private static void SetDynamicCachedCallSite(BinderHash hash, int knownBinderType, CallSite callSite) where T: class { switch (knownBinderType) { default: _allCaches.Add(BinderCache.ClearCache); BinderCache.Cache[hash] = callSite; break; case KnownGet: _allCaches.Add(BinderGetCache.ClearCache); BinderGetCache.Cache[hash] = callSite; break; case KnownSet: _allCaches.Add(BinderSetCache.ClearCache); BinderSetCache.Cache[hash] = callSite; break; case KnownMember: _allCaches.Add(BinderMemberCache.ClearCache); BinderMemberCache.Cache[hash] = callSite; break; case KnownDirect: _allCaches.Add(BinderDirectCache.ClearCache); BinderDirectCache.Cache[hash] = callSite; break; case KnownConstructor: _allCaches.Add(BinderConstructorCache.ClearCache); BinderConstructorCache.Cache[hash] = callSite; break; } } /// /// LazyBinderType /// internal delegate CallSiteBinder LazyBinder(); public static bool IsActionOrFunc(object target) { if (target == null) return false; var tType = target as Type ?? target.GetType(); if (tType.GetTypeInfo().IsGenericType) { tType = tType.GetGenericTypeDefinition(); } return FuncArgs.ContainsKey(tType) || ActionArgs.ContainsKey(tType); } internal static object InvokeMethodDelegate(this object target, Delegate tFunc, object[] args) { object result; try { result = tFunc.FastDynamicInvoke( tFunc.IsSpecialThisDelegate() ? new[] { target }.Concat(args).ToArray() : args ); } catch (TargetInvocationException ex) { if (ex.InnerException != null) throw ex.InnerException; throw; } return result; } internal static IEnumerable GetBindingArgumentList(object[] args, string[] argNames, bool staticContext) { var tTargetFlag = CSharpArgumentInfoFlags.None; if (staticContext) { tTargetFlag |= CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType; } var tList = new BareBonesList(args.Length + 1) { CSharpArgumentInfo.Create(tTargetFlag, null) }; //Optimization: linq statement creates a slight overhead in this case // ReSharper disable LoopCanBeConvertedToQuery // ReSharper disable ForCanBeConvertedToForeach for (int i = 0; i < args.Length; i++) { var tFlag = CSharpArgumentInfoFlags.None; string tName = null; if (argNames != null && argNames.Length > i) tName = argNames[i]; if (!String.IsNullOrEmpty(tName)) { tFlag |= CSharpArgumentInfoFlags.NamedArgument; } tList.Add(CSharpArgumentInfo.Create( tFlag, tName)); } // ReSharper restore ForCanBeConvertedToForeach // ReSharper restore LoopCanBeConvertedToQuery return tList; } internal static CallSite CreateCallSite( Type delegateType, Type specificBinderType, int knownType, LazyBinder binder, InvokeMemberName name, Type context, string[] argNames = null, bool staticContext = false, bool isEvent = false ) { CallSite tSite; bool foundInCache; lock (_callSiteCacheLock) { foundInCache = DynamicInvokeCreateCallSite.TryGetValue(delegateType, out tSite); } if (!foundInCache) { tSite = CallSite.Create( Binder.InvokeMember( CSharpBinderFlags.None, "CreateCallSite", new[] { delegateType }, typeof(InvokeHelper), new[] { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), // InvokeHelper CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //binderType CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //knownType CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //binder CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //name CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //context CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //argnames CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //staticcontext CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), //isevent } )); lock (_callSiteCacheLock) { // another thread might have been faster; add to dictionary only if we are the first if (!DynamicInvokeCreateCallSite.ContainsKey(delegateType)) { DynamicInvokeCreateCallSite[delegateType] = tSite; } } } return (CallSite)tSite.Target(tSite, typeof(InvokeHelper), specificBinderType, knownType, binder, name, context, argNames, staticContext, isEvent); } internal delegate object DynamicCreateCallSite( CallSite site, Type targetType, Type specificBinderType, int knownType, LazyBinder binder, InvokeMemberName name, Type context, string[] argNames, bool staticContext, bool isEvent ); internal static CallSite CreateCallSite( Type specificBinderType, int knownType, LazyBinder binder, InvokeMemberName name, Type context, string[] argNames = null, bool staticContext = false, bool isEvent = false ) where T : class { var tHash = BinderHash.Create(name, context, argNames, specificBinderType, staticContext, isEvent, knownType != Unknown); lock (_binderCacheLock) { if (!TryDynamicCachedCallSite(tHash, knownType, out var tOut)) { tOut = CallSite.Create(binder()); SetDynamicCachedCallSite(tHash, knownType, tOut); } return tOut; } } internal static CallSite CreateCallSite( Type specificBinderType, int knownType, LazyBinder binder, string name, Type context, string[] argNames = null, bool staticContext = false, bool isEvent = false ) where T : class { var tHash = BinderHash.Create(name, context, argNames, specificBinderType, staticContext, isEvent, knownType != Unknown); lock (_binderCacheLock) { if (!TryDynamicCachedCallSite(tHash, knownType, out var tOut)) { tOut = CallSite.Create(binder()); SetDynamicCachedCallSite(tHash, knownType, tOut); } return tOut; } } internal delegate object DynamicInvokeMemberConstructorValueType( CallSite funcSite, Type funcTarget, ref CallSite callsite, Type binderType, int knownType, LazyBinder binder, InvokeMemberName name, bool staticContext, Type context, string[] argNames, Type target, object[] args); internal static readonly IDictionary> _dynamicInvokeMemberSite = new Dictionary>(); internal static dynamic DynamicInvokeStaticMember(Type tReturn, ref CallSite callsite, Type binderType, int knownType, LazyBinder binder, InvokeMemberName name, bool staticContext, Type context, string[] argNames, Type target, params object[] args) { if (!_dynamicInvokeMemberSite.TryGetValue(tReturn, out var tSite)) { tSite = CallSite.Create( Binder.InvokeMember( CSharpBinderFlags.None, "InvokeMemberTargetType", new[] { typeof(Type), tReturn }, typeof(InvokeHelper), new[] { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsRef, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), } ) ); _dynamicInvokeMemberSite[tReturn] = tSite; } return tSite.Target(tSite, typeof(InvokeHelper), ref callsite, binderType, knownType, binder, name, staticContext, context, argNames, target, args); } internal static TReturn InvokeMember(ref CallSite callsite, Type binderType,int knownType, LazyBinder binder, InvokeMemberName name, bool staticContext, Type context, string[] argNames, object target, params object[] args) { return InvokeMemberTargetType(ref callsite, binderType, knownType, binder, name, staticContext, context, argNames, target, args); } internal static object InvokeGetCallSite(object target, string name, Type context, bool staticContext, ref CallSite callsite) { if (callsite == null) { var tTargetFlag = CSharpArgumentInfoFlags.None; LazyBinder tBinder; Type tBinderType; int tKnownType; if (staticContext) //CSharp Binder won't call Static properties, grrr. { var tStaticFlag = CSharpBinderFlags.None; if ((target is Type && ((Type)target).GetTypeInfo().IsPublic)) { tBinder = () => Binder.InvokeMember(tStaticFlag, "get_" + name, null, context, new List { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null) }); tBinderType = typeof (InvokeMemberBinder); tKnownType = KnownMember; } else { tBinder = () => Binder.GetMember(tStaticFlag, name, context, new List { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.IsStaticType, null) }); tBinderType = typeof(InvokeMemberBinder); tKnownType = KnownMember; } } else { tBinder =()=> Binder.GetMember(CSharpBinderFlags.None, name, context, new List { CSharpArgumentInfo.Create( tTargetFlag, null) }); tBinderType = typeof(GetMemberBinder); tKnownType = KnownGet; } callsite = CreateCallSite>(tBinderType,tKnownType, tBinder, name, context, staticContext: staticContext); } var tCallSite = (CallSite>) callsite; return tCallSite.Target(tCallSite, target); } internal static object InvokeSetCallSite(object target, string name, object value, Type context, bool staticContext, ref CallSite callSite) { if (callSite == null) { LazyBinder tBinder; Type tBinderType; if (staticContext) //CSharp Binder won't call Static properties, grrr. { tBinder = () =>{ var tStaticFlag = CSharpBinderFlags.ResultDiscarded; return Binder.InvokeMember(tStaticFlag, "set_" + name, null, context, new List { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.None , null) }); }; tBinderType = typeof(InvokeMemberBinder); callSite = CreateCallSite>(tBinderType,KnownMember, tBinder, name, context, staticContext:true); } else { tBinder = ()=> Binder.SetMember(CSharpBinderFlags.None, name, context, new List { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.None , null) }); tBinderType = typeof(SetMemberBinder); callSite = CreateCallSite>(tBinderType,KnownSet, tBinder, name, context, staticContext: false); } } if (staticContext) { var tCallSite = (CallSite>) callSite; tCallSite.Target(callSite, target, value); return value; } else { var tCallSite = (CallSite>) callSite; var tResult = tCallSite.Target(callSite, target, value); return tResult; } } internal static object InvokeMemberCallSite(object target, InvokeMemberName name, object[] args, string[] tArgNames, Type tContext, bool tStaticContext, ref CallSite callSite) { LazyBinder tBinder = null; Type tBinderType = null; if (callSite == null) { tBinder = () => { var tList = GetBindingArgumentList(args, tArgNames, tStaticContext); var tFlag = CSharpBinderFlags.None; if (name.IsSpecialName) { tFlag |= CSharpBinderFlags.InvokeSpecialName; } return Binder.InvokeMember(tFlag, name.Name, name.GenericArgs, tContext, tList); }; tBinderType = typeof (InvokeMemberBinder); } return InvokeMember(ref callSite, tBinderType, KnownMember, tBinder, name, tStaticContext, tContext, tArgNames, target, args); } internal static object InvokeDirectCallSite(object target, object[] args, string[] tArgNames, Type tContext, bool tStaticContext, ref CallSite callSite) { LazyBinder tBinder = null; Type tBinderType = null; if (callSite == null) { tBinder = () => { var tList = GetBindingArgumentList(args, tArgNames, tStaticContext); var tFlag = CSharpBinderFlags.None; return Binder.Invoke(tFlag,tContext, tList); }; tBinderType = typeof(InvokeBinder); } return InvokeMember(ref callSite, tBinderType, KnownDirect,tBinder, String.Empty, tStaticContext, tContext, tArgNames, target, args); } internal static object InvokeGetIndexCallSite(object target, object[] indexes, string[] argNames, Type context, bool tStaticContext,ref CallSite callSite) { LazyBinder tBinder=null; Type tBinderType = null; if (callSite == null) { tBinder = () => { var tList = GetBindingArgumentList(indexes, argNames, tStaticContext); return Binder.GetIndex(CSharpBinderFlags.None, context, tList); }; tBinderType = typeof (GetIndexBinder); } return InvokeMember(ref callSite,tBinderType, Unknown, tBinder, Invocation.IndexBinderName, tStaticContext, context, argNames, target, indexes); } internal static object InvokeSetIndexCallSite(object target, object[] indexesThenValue, string[] tArgNames, Type tContext, bool tStaticContext, ref CallSite tCallSite) { LazyBinder tBinder =null; Type tBinderType = null; if (tCallSite == null) { tBinder = () => { var tList = GetBindingArgumentList(indexesThenValue, tArgNames, tStaticContext); return Binder.SetIndex(CSharpBinderFlags.None, tContext, tList); }; tBinderType = typeof (SetIndexBinder); } return InvokeMember(ref tCallSite, tBinderType, Unknown, tBinder, Invocation.IndexBinderName, tStaticContext, tContext, tArgNames, target, indexesThenValue); } internal static void InvokeMemberActionCallSite(object target,InvokeMemberName name, object[] args, string[] tArgNames, Type tContext, bool tStaticContext,ref CallSite callSite) { LazyBinder tBinder =null; Type tBinderType = null; if (callSite == null) { tBinder = () => { IEnumerable tList; tList = GetBindingArgumentList(args, tArgNames, tStaticContext); var tFlag = CSharpBinderFlags.ResultDiscarded; if (name.IsSpecialName) { tFlag |= CSharpBinderFlags.InvokeSpecialName; } return Binder.InvokeMember(tFlag, name.Name, name.GenericArgs, tContext, tList); }; tBinderType = typeof (InvokeMemberBinder); } InvokeMemberAction(ref callSite,tBinderType, KnownMember, tBinder, name, tStaticContext, tContext, tArgNames, target, args); } internal static void InvokeDirectActionCallSite(object target, object[] args, string[] tArgNames, Type tContext, bool tStaticContext, ref CallSite callSite) { LazyBinder tBinder = null; Type tBinderType = null; if (callSite == null) { tBinder = () => { IEnumerable tList; tList = GetBindingArgumentList(args, tArgNames, tStaticContext); var tFlag = CSharpBinderFlags.ResultDiscarded; return Binder.Invoke(tFlag,tContext, tList); }; tBinderType = typeof(InvokeBinder); } InvokeMemberAction(ref callSite, tBinderType, KnownDirect, tBinder, String.Empty, tStaticContext, tContext, tArgNames, target, args); } internal class IsEventBinderDummy{ } internal static bool InvokeIsEventCallSite(object target, string name, Type tContext, ref CallSite callSite) { if (callSite == null) { LazyBinder tBinder = ()=> Binder.IsEvent(CSharpBinderFlags.None, name, tContext); var tBinderType = typeof (IsEventBinderDummy); callSite = CreateCallSite>(tBinderType, Unknown, tBinder, name, tContext, isEvent: true); } var tCallSite = (CallSite>)callSite; return tCallSite.Target(tCallSite, target); } internal static void InvokeAddAssignCallSite(object target, string name, object[] args, string[] argNames, Type context, bool staticContext, //lgtm [cs/too-many-ref-parameters] ref CallSite callSiteIsEvent, ref CallSite callSiteAdd, ref CallSite callSiteGet, ref CallSite callSiteSet) //This is an optimization readability isn't the concern. { if (InvokeIsEventCallSite(target, name, context, ref callSiteIsEvent)) { InvokeMemberActionCallSite(target, InvokeMemberName.CreateSpecialName("add_" + name), args, argNames, context, staticContext, ref callSiteAdd); } else { dynamic tGet = InvokeGetCallSite(target,name, context, staticContext, ref callSiteGet); tGet += (dynamic)(args[0]); InvokeSetCallSite(target, name, (object)tGet, context, staticContext, ref callSiteSet); } } internal static void InvokeSubtractAssignCallSite(object target, string name, object[] args, string[] argNames, Type context, bool staticContext, // lgtm [cs/too-many-ref-parameters] ref CallSite callSiteIsEvent, ref CallSite callSiteRemove, ref CallSite callSiteGet, ref CallSite callSiteSet) //This is an optimization readability isn't the concern. { if (InvokeIsEventCallSite(target, name, context, ref callSiteIsEvent)) { InvokeMemberActionCallSite(target, InvokeMemberName.CreateSpecialName("remove_" + name), args, argNames, context, staticContext, ref callSiteRemove); } else { dynamic tGet = InvokeGetCallSite(target, name, context, staticContext, ref callSiteGet); tGet -= (dynamic)(args[0]); InvokeHelper.InvokeSetCallSite(target, name, tGet, context, staticContext, ref callSiteSet); } } public delegate void DynamicAction(params object[] args); public delegate TReturn DynamicFunc(params object[] args); internal static object InvokeConvertCallSite(object target, bool explict, Type type, Type context, ref CallSite callSite) { if (callSite == null) { LazyBinder tBinder = () => { var tFlags = explict ? CSharpBinderFlags.ConvertExplicit : CSharpBinderFlags.None; return Binder.Convert(tFlags, type, context); }; Type tBinderType = typeof (ConvertBinder); var tFunc = typeof(Func<,,>).MakeGenericType(typeof(CallSite), typeof(object), type); callSite = CreateCallSite(tFunc, tBinderType,Unknown, tBinder, explict ? Invocation.ExplicitConvertBinderName : Invocation.ImplicitConvertBinderName, context); } dynamic tDynCallSite = callSite; return tDynCallSite.Target(callSite, target); } internal class InvokeConstructorDummy{}; internal static InvokeMemberName ConstructorName = new InvokeMemberName(Invocation.ConstructorBinderName); internal static object InvokeConstructorCallSite(Type type, bool isValueType, object[] args, string[] argNames, ref CallSite callSite) { LazyBinder tBinder = null; Type tBinderType = typeof (InvokeConstructorDummy); if (callSite == null || isValueType) { if (isValueType && args.Length == 0) //dynamic invocation doesn't see no argument constructors of value types { return Activator.CreateInstance(type); } tBinder = () => { var tList = GetBindingArgumentList(args, argNames, true); return Binder.InvokeConstructor(CSharpBinderFlags.None, type, tList); }; } if (isValueType) { CallSite tDummy =null; return DynamicInvokeStaticMember(type, ref tDummy, tBinderType, KnownConstructor, tBinder, ConstructorName, true, type, argNames, type, args); } return InvokeMemberTargetType(ref callSite, tBinderType, KnownConstructor, tBinder, ConstructorName, true, type, argNames, type, args); } internal static readonly IDictionary> _dynamicInvokeWrapFunc = new Dictionary>(); internal delegate object DynamicInvokeWrapFunc( CallSite funcSite, Type funcTarget, object invokable, int length ); internal static Delegate WrapFunc(Type returnType, object invokable, int length) { if (!_dynamicInvokeWrapFunc.TryGetValue(returnType, out var tSite)) { var tMethod = "WrapFuncHelper"; tSite = CallSite.Create( Binder.InvokeMember( CSharpBinderFlags.None, tMethod, new[] {returnType}, typeof (InvokeHelper), new[] { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null), } )); _dynamicInvokeWrapFunc[returnType] = tSite; } return (Delegate) tSite.Target(tSite, typeof(InvokeHelper), invokable, length); } } } ================================================ FILE: Dynamitey/Internal/Optimization/InvokeHelper.cs ================================================  // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Reflection; namespace Dynamitey.Internal.Optimization { internal static class BinderCache where T : class { private static IDictionary, CallSite> _cache; private static readonly object _cacheLock = new object(); internal static IDictionary, CallSite> Cache { get { lock (_cacheLock) { return _cache ?? (_cache = new Dictionary, CallSite>()); } } } internal static readonly Action ClearCache = () => { lock (_cacheLock) { _cache = null; } }; } internal static class BinderGetCache where T : class { private static IDictionary, CallSite> _cache; private static readonly object _cacheLock = new object(); internal static IDictionary, CallSite> Cache { get { lock (_cacheLock) { return _cache ?? (_cache = new Dictionary, CallSite>()); } } } internal static readonly Action ClearCache = () => { lock (_cacheLock) { _cache = null; } }; } internal static class BinderSetCache where T : class { private static IDictionary, CallSite> _cache; private static readonly object _cacheLock = new object(); internal static IDictionary, CallSite> Cache { get { lock (_cacheLock) { return _cache ?? (_cache = new Dictionary, CallSite>()); } } } internal static readonly Action ClearCache = () => { lock (_cacheLock) { _cache = null; } }; } internal static class BinderConstructorCache where T : class { private static IDictionary, CallSite> _cache; private static readonly object _cacheLock = new object(); internal static IDictionary, CallSite> Cache { get { lock (_cacheLock) { return _cache ?? (_cache = new Dictionary, CallSite>()); } } } internal static readonly Action ClearCache = () => { lock (_cacheLock) { _cache = null; } }; } internal static class BinderMemberCache where T : class { private static IDictionary, CallSite> _cache; private static readonly object _cacheLock = new object(); internal static IDictionary, CallSite> Cache { get { lock (_cacheLock) { return _cache ?? (_cache = new Dictionary, CallSite>()); } } } internal static readonly Action ClearCache = () => { lock (_cacheLock) { _cache = null; } }; } internal static class BinderDirectCache where T : class { private static IDictionary, CallSite> _cache; private static readonly object _cacheLock = new object(); internal static IDictionary, CallSite> Cache { get { lock (_cacheLock) { return _cache ?? (_cache = new Dictionary, CallSite>()); } } } internal static readonly Action ClearCache = () => { lock (_cacheLock) { _cache = null; } }; } internal static partial class InvokeHelper { internal static readonly Type[] FuncKinds; internal static readonly Type[] ActionKinds; internal static readonly Type[] TupleKinds; internal static readonly IDictionary FuncArgs; internal static readonly IDictionary ActionArgs; internal static readonly IDictionary TupleArgs; static InvokeHelper() { FuncKinds = new [] { typeof(Func<>), //0 typeof(Func<,>), //1 typeof(Func<,,>), //2 typeof(Func<,,,>), //3 typeof(Func<,,,,>), //4 typeof(Func<,,,,,>), //5 typeof(Func<,,,,,,>), //6 typeof(Func<,,,,,,,>), //7 typeof(Func<,,,,,,,,>), //8 typeof(Func<,,,,,,,,,>), //9 typeof(Func<,,,,,,,,,,>), //10 typeof(Func<,,,,,,,,,,,>), //11 typeof(Func<,,,,,,,,,,,,>), //12 typeof(Func<,,,,,,,,,,,,,>), //13 typeof(Func<,,,,,,,,,,,,,,>), //14 typeof(Func<,,,,,,,,,,,,,,,>), //15 typeof(Func<,,,,,,,,,,,,,,,,>), //16 }; ActionKinds = new [] { typeof(Action), //0 typeof(Action<>), //1 typeof(Action<,>), //2 typeof(Action<,,>), //3 typeof(Action<,,,>), //4 typeof(Action<,,,,>), //5 typeof(Action<,,,,,>), //6 typeof(Action<,,,,,,>), //7 typeof(Action<,,,,,,,>), //8 typeof(Action<,,,,,,,,>), //9 typeof(Action<,,,,,,,,,>), //10 typeof(Action<,,,,,,,,,,>), //11 typeof(Action<,,,,,,,,,,,>), //12 typeof(Action<,,,,,,,,,,,,>), //13 typeof(Action<,,,,,,,,,,,,,>), //14 typeof(Action<,,,,,,,,,,,,,,>), //15 typeof(Action<,,,,,,,,,,,,,,,>), //16 }; TupleKinds = new [] { typeof(Tuple<>), //1 typeof(Tuple<,>), //2 typeof(Tuple<,,>), //3 typeof(Tuple<,,,>), //4 typeof(Tuple<,,,,>), //5 typeof(Tuple<,,,,,>), //6 typeof(Tuple<,,,,,,>), //7 typeof(Tuple<,,,,,,,>), //8 }; FuncArgs = FuncKinds.Zip(Enumerable.Range(0, FuncKinds.Length), (key, value) => new { key, value }).ToDictionary(k => k.key, v => v.value); ActionArgs = ActionKinds.Zip(Enumerable.Range(0, ActionKinds.Length), (key, value) => new { key, value }).ToDictionary(k => k.key, v => v.value); TupleArgs = TupleKinds.Zip(Enumerable.Range(1, ActionKinds.Length), (key, value) => new { key, value }).ToDictionary(k => k.key, v => v.value); } internal static dynamic TupleItem(dynamic tuple, int index){ switch(index){ case 1: return tuple.Item1; case 2: return tuple.Item2; case 3: return tuple.Item3; case 4: return tuple.Item4; case 5: return tuple.Item5; case 6: return tuple.Item6; case 7: return tuple.Item7; default: return tuple.Rest; } } internal static void InvokeMemberAction(ref CallSite callsite, Type binderType, int knownType, LazyBinder binder, InvokeMemberName name, bool staticContext, Type context, string[] argNames, object target, params object [] args) { var tSwitch = args.Length; switch (tSwitch) { #region Optimizations case 0: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target); break; } case 1: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0]); break; } case 2: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1]); break; } case 3: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2]); break; } case 4: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3]); break; } case 5: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4]); break; } case 6: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5]); break; } case 7: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break; } case 8: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break; } case 9: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break; } case 10: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); break; } case 11: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); break; } case 12: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]); break; } case 13: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]); break; } case 14: { var tCallSite = (CallSite>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]); break; } #endregion default: var tArgTypes = Enumerable.Repeat(typeof(object), tSwitch); var tDelagateType = EmitCallSiteFuncType(tArgTypes, typeof(void)); Dynamic.InvokeCallSite(CreateCallSite(tDelagateType, binderType,knownType, binder, name, context, argNames), target, args); break; } } internal static TReturn InvokeMemberTargetType( ref CallSite callsite, Type binderType, int knownType, LazyBinder binder, InvokeMemberName name, bool staticContext, Type context, string[] argNames, TTarget target, params object [] args) { var tSwitch = args.Length; switch (tSwitch) { #region Optimizations case 0: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target); } case 1: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0]); } case 2: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1]); } case 3: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2]); } case 4: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3]); } case 5: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4]); } case 6: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5]); } case 7: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); } case 8: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); } case 9: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); } case 10: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); } case 11: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); } case 12: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]); } case 13: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]); } case 14: { var tCallSite = (CallSite>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]); } #endregion default: var tArgTypes = Enumerable.Repeat(typeof(object), tSwitch); var tDelagateType = EmitCallSiteFuncType(tArgTypes, typeof(TTarget)); return Dynamic.InvokeCallSite(CreateCallSite(tDelagateType, binderType,knownType, binder, name, context, argNames), target, args); } } internal static Delegate WrapFuncHelper(dynamic invokable, int length) { switch(length){ #region Optimizations case 0: return new Func< TReturn>(()=> invokable()); case 1: return new Func< object, TReturn>((a1)=> invokable(a1)); case 2: return new Func< object, object, TReturn>((a1,a2)=> invokable(a1,a2)); case 3: return new Func< object, object, object, TReturn>((a1,a2,a3)=> invokable(a1,a2,a3)); case 4: return new Func< object, object, object, object, TReturn>((a1,a2,a3,a4)=> invokable(a1,a2,a3,a4)); case 5: return new Func< object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5)=> invokable(a1,a2,a3,a4,a5)); case 6: return new Func< object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6)=> invokable(a1,a2,a3,a4,a5,a6)); case 7: return new Func< object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7)=> invokable(a1,a2,a3,a4,a5,a6,a7)); case 8: return new Func< object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8)); case 9: return new Func< object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9)); case 10: return new Func< object, object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)); case 11: return new Func< object, object, object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)); case 12: return new Func< object, object, object, object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)); case 13: return new Func< object, object, object, object, object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)); case 14: return new Func< object, object, object, object, object, object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)); case 15: return new Func< object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)); case 16: return new Func< object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, TReturn>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)); #endregion default: return new DynamicFunc(args=>(TReturn)Dynamic.Invoke((object)invokable,args)); } } internal static Delegate WrapAction(dynamic invokable, int length) { switch(length){ #region Optimizations case 0: return new Action(()=>invokable()); case 1: return new Action< object>((a1)=> invokable(a1)); case 2: return new Action< object, object>((a1,a2)=> invokable(a1,a2)); case 3: return new Action< object, object, object>((a1,a2,a3)=> invokable(a1,a2,a3)); case 4: return new Action< object, object, object, object>((a1,a2,a3,a4)=> invokable(a1,a2,a3,a4)); case 5: return new Action< object, object, object, object, object>((a1,a2,a3,a4,a5)=> invokable(a1,a2,a3,a4,a5)); case 6: return new Action< object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6)=> invokable(a1,a2,a3,a4,a5,a6)); case 7: return new Action< object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7)=> invokable(a1,a2,a3,a4,a5,a6,a7)); case 8: return new Action< object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8)); case 9: return new Action< object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9)); case 10: return new Action< object, object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)); case 11: return new Action< object, object, object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)); case 12: return new Action< object, object, object, object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)); case 13: return new Action< object, object, object, object, object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13)); case 14: return new Action< object, object, object, object, object, object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)); case 15: return new Action< object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)); case 16: return new Action< object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>((a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)=> invokable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)); #endregion default: return new DynamicAction(args=>Dynamic.InvokeAction((object)invokable,args)); } } internal static object FastDynamicInvokeReturn(Delegate del, dynamic [] args) { dynamic tDel =del; switch(args.Length){ default: try { return del.DynamicInvoke(args); } catch (TargetInvocationException ex) { throw ex.InnerException; } #region Optimization case 1: return tDel(args[0]); case 2: return tDel(args[0],args[1]); case 3: return tDel(args[0],args[1],args[2]); case 4: return tDel(args[0],args[1],args[2],args[3]); case 5: return tDel(args[0],args[1],args[2],args[3],args[4]); case 6: return tDel(args[0],args[1],args[2],args[3],args[4],args[5]); case 7: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6]); case 8: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]); case 9: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]); case 10: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]); case 11: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]); case 12: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]); case 13: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]); case 14: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]); case 15: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14]); case 16: return tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15]); #endregion } } internal static void FastDynamicInvokeAction(Delegate del, params dynamic [] args) { dynamic tDel =del; switch(args.Length){ default: try { del.DynamicInvoke(args); } catch (TargetInvocationException ex) { throw ex.InnerException; } return; #region Optimization case 1: tDel(args[0]); return; case 2: tDel(args[0],args[1]); return; case 3: tDel(args[0],args[1],args[2]); return; case 4: tDel(args[0],args[1],args[2],args[3]); return; case 5: tDel(args[0],args[1],args[2],args[3],args[4]); return; case 6: tDel(args[0],args[1],args[2],args[3],args[4],args[5]); return; case 7: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6]); return; case 8: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]); return; case 9: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]); return; case 10: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]); return; case 11: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]); return; case 12: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]); return; case 13: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]); return; case 14: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]); return; case 15: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14]); return; case 16: tDel(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15]); return; #endregion } } } } ================================================ FILE: Dynamitey/Internal/Optimization/InvokeHelper.tt ================================================ <#@ template language="C#" #> <#@ output extension="cs" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Reflection; namespace Dynamitey.Internal.Optimization { <# var cacheTypes = new []{"", "Get", "Set", "Constructor", "Member", "Direct"}; #> <# foreach(var name in cacheTypes){ #> internal static class Binder<#=name#>Cache where T : class { private static IDictionary, CallSite> _cache; private static readonly object _cacheLock = new object(); internal static IDictionary, CallSite> Cache { get { lock (_cacheLock) { return _cache ?? (_cache = new Dictionary, CallSite>()); } } } internal static readonly Action ClearCache = () => { lock (_cacheLock) { _cache = null; } }; } <# } #> internal static partial class InvokeHelper { internal static readonly Type[] FuncKinds; internal static readonly Type[] ActionKinds; internal static readonly Type[] TupleKinds; internal static readonly IDictionary FuncArgs; internal static readonly IDictionary ActionArgs; internal static readonly IDictionary TupleArgs; static InvokeHelper() { FuncKinds = new [] { <# for(int i=0; i <= 16; i++){ var tCommas = String.Concat(Enumerable.Repeat(",",i)); #> typeof(Func<<#=tCommas#>>), //<#=i#> <# } #> }; ActionKinds = new [] { typeof(Action), //0 <# for(int i=1; i <= 16; i++){ var tCommas = String.Concat(Enumerable.Repeat(",",i-1)); #> typeof(Action<<#=tCommas#>>), //<#=i#> <# } #> }; TupleKinds = new [] { <# for(int i=1; i <= 8; i++){ var tCommas = String.Concat(Enumerable.Repeat(",",i-1)); #> typeof(Tuple<<#=tCommas#>>), //<#=i#> <# } #> }; FuncArgs = FuncKinds.Zip(Enumerable.Range(0, FuncKinds.Length), (key, value) => new { key, value }).ToDictionary(k => k.key, v => v.value); ActionArgs = ActionKinds.Zip(Enumerable.Range(0, ActionKinds.Length), (key, value) => new { key, value }).ToDictionary(k => k.key, v => v.value); TupleArgs = TupleKinds.Zip(Enumerable.Range(1, ActionKinds.Length), (key, value) => new { key, value }).ToDictionary(k => k.key, v => v.value); } internal static dynamic TupleItem(dynamic tuple, int index){ switch(index){ <# for(int i=1; i <= 7; i++){ #> case <#=i#>: return tuple.Item<#=i#>; <# } #> default: return tuple.Rest; } } internal static void InvokeMemberAction(ref CallSite callsite, Type binderType, int knownType, LazyBinder binder, InvokeMemberName name, bool staticContext, Type context, string[] argNames, object target, params object [] args) { var tSwitch = args.Length; switch (tSwitch) { #region Optimizations <# for(int i=0; i <= 14; i++){ var tobjectArgs = String.Join(",",Enumerable.Repeat(" object",i+1)); var tArrayArgs = String.Concat(Enumerable.Range(0,i).Select(it=>String.Format(", args[{0}]",it))); #> case <#=i#>: { var tCallSite = (CallSite>>)callsite; if(tCallSite == null){ tCallSite = CreateCallSite>>(binderType,knownType, binder, name, context, argNames, staticContext); callsite=tCallSite; } tCallSite.Target(tCallSite, target<#=tArrayArgs#>); break; } <# } #> #endregion default: var tArgTypes = Enumerable.Repeat(typeof(object), tSwitch); var tDelagateType = EmitCallSiteFuncType(tArgTypes, typeof(void)); Dynamic.InvokeCallSite(CreateCallSite(tDelagateType, binderType,knownType, binder, name, context, argNames), target, args); break; } } internal static TReturn InvokeMemberTargetType( ref CallSite callsite, Type binderType, int knownType, LazyBinder binder, InvokeMemberName name, bool staticContext, Type context, string[] argNames, TTarget target, params object [] args) { var tSwitch = args.Length; switch (tSwitch) { #region Optimizations <# for(int i=0; i <= 14; i++){ var tobjectArgs = String.Join(",",Enumerable.Repeat(" object",i).Concat(new[]{"TReturn"})); var tArrayArgs = String.Concat(Enumerable.Range(0,i).Select(it=>String.Format(", args[{0}]",it))); #> case <#=i#>: { var tCallSite = (CallSite>>)callsite; if(tCallSite==null){ tCallSite = CreateCallSite>>(binderType,knownType,binder, name, context, argNames, staticContext); callsite =tCallSite; } return tCallSite.Target(tCallSite, target<#=tArrayArgs#>); } <# } #> #endregion default: var tArgTypes = Enumerable.Repeat(typeof(object), tSwitch); var tDelagateType = EmitCallSiteFuncType(tArgTypes, typeof(TTarget)); return Dynamic.InvokeCallSite(CreateCallSite(tDelagateType, binderType,knownType, binder, name, context, argNames), target, args); } } internal static Delegate WrapFuncHelper(dynamic invokable, int length) { switch(length){ #region Optimizations <# for(int i=0; i <= 16; i++){ var tobjectArgs = String.Join(",",Enumerable.Repeat(" object",i).Concat(new[]{" TReturn"})); var tArgList = String.Join(",",Enumerable.Range(0,i).Select(it=>"a"+(it+1))); #> case <#=i#>: return new Func<<#=tobjectArgs#>>((<#=tArgList#>)=> invokable(<#=tArgList#>)); <# } #> #endregion default: return new DynamicFunc(args=>(TReturn)Dynamic.Invoke((object)invokable,args)); } } internal static Delegate WrapAction(dynamic invokable, int length) { switch(length){ #region Optimizations case 0: return new Action(()=>invokable()); <# for(int i=1; i <= 16; i++){ var tobjectArgs = String.Join(",",Enumerable.Repeat(" object",i)); var tArgList = String.Join(",",Enumerable.Range(0,i).Select(it=>"a"+(it+1))); #> case <#=i#>: return new Action<<#=tobjectArgs#>>((<#=tArgList#>)=> invokable(<#=tArgList#>)); <# } #> #endregion default: return new DynamicAction(args=>Dynamic.InvokeAction((object)invokable,args)); } } internal static object FastDynamicInvokeReturn(Delegate del, dynamic [] args) { dynamic tDel =del; switch(args.Length){ default: try { return del.DynamicInvoke(args); } catch (TargetInvocationException ex) { throw ex.InnerException; } #region Optimization <# for(int i=1; i <= 16; i++){ var tArgs = String.Join(",",Enumerable.Range(0,i).Select(it=>String.Format("args[{0}]",it))); #> case <#=i#>: return tDel(<#= tArgs #>); <# } #> #endregion } } internal static void FastDynamicInvokeAction(Delegate del, params dynamic [] args) { dynamic tDel =del; switch(args.Length){ default: try { del.DynamicInvoke(args); } catch (TargetInvocationException ex) { throw ex.InnerException; } return; #region Optimization <# for(int i=1; i <= 16; i++){ var tArgs = String.Join(",",Enumerable.Range(0,i).Select(it=>String.Format("args[{0}]",it))); #> case <#=i#>: tDel(<#= tArgs #>); return; <# } #> #endregion } } } } ================================================ FILE: Dynamitey/Internal/Optimization/Util.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.ComponentModel; using System.Dynamic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using Dynamitey.DynamicObjects; using Microsoft.CSharp.RuntimeBinder; using Dynamitey.Internal.Compat; namespace Dynamitey.Internal.Optimization { /// /// Utility Class /// public static class Util { /// /// Is Current Runtime Mono? /// public static readonly bool IsMono; static Util() { IsMono = Type.GetType("Mono.Runtime") != null; } /// /// Determines whether [is anonymous type] [the specified target]. /// /// The target. /// /// true if [is anonymous type] [the specified target]; otherwise, false. /// public static bool IsAnonymousType(object target) { if (target == null) return false; var type = target as Type ?? target.GetType(); var typeinfo = type.GetTypeInfo(); return typeinfo.IsNotPublic && typeinfo.IsDefined( typeof(CompilerGeneratedAttribute), false); } /// /// Names the args if necessary. /// /// The call info. /// The args. /// public static object[] NameArgsIfNecessary(CallInfo callInfo, object[] args) { object[] tArgs; if (callInfo.ArgumentNames.Count == 0) tArgs = args; else { var tStop = callInfo.ArgumentCount - callInfo.ArgumentNames.Count; tArgs = Enumerable.Repeat(default(string), tStop).Concat(callInfo.ArgumentNames).Zip(args, (n, v) => n == null ? v : new InvokeArg(n, v)).ToArray(); } return tArgs; } /// /// Gets the target context. /// /// The target. /// The context. /// if set to true [static context]. /// public static object GetTargetContext(this object target, out Type context, out bool staticContext) { var tInvokeContext = target as InvokeContext; staticContext = false; if (tInvokeContext != null) { staticContext = tInvokeContext.StaticContext; context = tInvokeContext.Context; context = context.FixContext(); return tInvokeContext.Target; } context = target as Type ?? target.GetType(); context = context.FixContext(); return target; } /// /// Fixes the context. /// /// The context. /// public static Type FixContext(this Type context) { if (context.IsArray) { return typeof (object); } return context; } internal static bool MassageResultBasedOnInterface(this BaseObject target, string binderName, bool resultFound, ref object result) { if (result is BaseForwarder.AddRemoveMarker) //Don't massage AddRemove Proxies return true; var tTryType = target.TryTypeForName(binderName, out var tType); if (tTryType && tType == typeof(void)) { return true; } if(resultFound){ if (result is IDictionary && !(result is BaseDictionary) && (!tTryType || tType == typeof(object))) { result = new Dictionary((IDictionary)result); } else if (tTryType) { result = Dynamic.CoerceConvert(result, tType); } } else { result = null; if (!tTryType) { return false; } if (typeof (Delegate).GetTypeInfo().IsAssignableFrom(tType)) { result = new BaseForwarder.AddRemoveMarker(); } if (tType.GetTypeInfo().IsValueType) { result = Dynamic.InvokeConstructor(tType); } } return true; } internal static object[] GetArgsAndNames(object[]args,out string[]argNames) { if (args == null) args = new object[] { null }; //Optimization: linq statement creates a slight overhead in this case // ReSharper disable LoopCanBeConvertedToQuery // ReSharper disable ForCanBeConvertedToForeach argNames = new string[args.Length]; var tArgSet = false; var tNewArgs = new object[args.Length]; for (int i = 0; i < args.Length; i++) { var tArg = args[i]; string tName = null; if (tArg is InvokeArg) { tName = ((InvokeArg)tArg).Name; tNewArgs[i] = ((InvokeArg)tArg).Value; tArgSet = true; }else { tNewArgs[i] = tArg; } argNames[i] = tName; } // ReSharper restore ForCanBeConvertedToForeach // ReSharper restore LoopCanBeConvertedToQuery if (!tArgSet) argNames = null; return tNewArgs; } } } ================================================ FILE: Dynamitey/Invocation.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Linq; using Microsoft.CSharp.RuntimeBinder; namespace Dynamitey { /// /// Type of Invocation /// public enum InvocationKind { /// /// NotSet /// NotSet=0, /// /// Convert Implicit or Explicity /// Convert, /// /// Get Property /// Get, /// /// Set Property /// Set, /// /// Get Indexer /// GetIndex, /// /// Set Indexer /// SetIndex, /// /// Invoke Method the has return value /// InvokeMember, /// /// Invoke Method that returns void /// InvokeMemberAction, /// /// Invoke Method that could return a value or void /// InvokeMemberUnknown, /// /// Invoke Constructor /// Constructor, /// /// Invoke += /// AddAssign, /// /// Invoke -= /// SubtractAssign, /// /// Invoke Event Property Test /// IsEvent, /// /// Invoke Directly /// Invoke, /// /// Invoke Directly DiscardResult /// InvokeAction, /// /// Invoke Directly Return Value /// InvokeUnknown, } /// /// Storable representation of an invocation without the target /// public class Invocation { /// /// Defacto Binder Name for Explicit Convert Op /// public static readonly string ExplicitConvertBinderName = "(Explicit)"; /// /// Defacto Binder Name for Implicit Convert Op /// public static readonly string ImplicitConvertBinderName = "(Implicit)"; /// /// Defacto Binder Name for Indexer /// public static readonly string IndexBinderName = "Item"; /// /// Defacto Binder Name for Constructor /// public static readonly string ConstructorBinderName = "new()"; /// /// Gets or sets the kind. /// /// The kind. public InvocationKind Kind { get; protected set; } /// /// Gets or sets the name. /// /// The name. public String_OR_InvokeMemberName Name { get; protected set; } /// /// Gets or sets the args. /// /// The args. public object[] Args { get; protected set; } /// /// Creates the invocation. /// /// The kind. /// The name. /// The args. /// public static Invocation Create(InvocationKind kind, String_OR_InvokeMemberName name, params object[] storedArgs) { return new Invocation(kind,name,storedArgs); } /// /// Initializes a new instance of the class. /// /// The kind. /// The name. /// The args. public Invocation(InvocationKind kind, String_OR_InvokeMemberName name, params object[] storedArgs) { Kind = kind; Name = name; Args = storedArgs; } /// /// Equalses the specified other. /// /// The other. /// public bool Equals(Invocation other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(other.Kind, Kind) && Equals(other.Name, Name) && (Equals(other.Args, Args) || Enumerable.SequenceEqual(other.Args, Args)); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != typeof (Invocation)) return false; return Equals((Invocation) obj); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { unchecked { int result = Kind.GetHashCode(); result = (result*397) ^ (Name != null ? Name.GetHashCode() : 0); result = (result*397) ^ (Args != null ? Args.GetHashCode() : 0); return result; } } /// /// Invokes the invocation on specified target with specific args. /// /// The target. /// The args. /// public virtual object Invoke(object target, params object[] args) { switch (Kind) { case InvocationKind.Constructor: return Dynamic.InvokeConstructor((Type)target, args); case InvocationKind.Convert: bool tExplicit = false; if (Args.Length == 2) tExplicit = (bool)args[1]; return Dynamic.InvokeConvert(target, (Type)args[0], tExplicit); case InvocationKind.Get: return Dynamic.InvokeGet(target, Name.Name); case InvocationKind.Set: Dynamic.InvokeSet(target, Name.Name, args.FirstOrDefault()); return null; case InvocationKind.GetIndex: return Dynamic.InvokeGetIndex(target, args); case InvocationKind.SetIndex: Dynamic.InvokeSetIndex(target, args); return null; case InvocationKind.InvokeMember: return Dynamic.InvokeMember(target, Name, args); case InvocationKind.InvokeMemberAction: Dynamic.InvokeMemberAction(target, Name, args); return null; case InvocationKind.InvokeMemberUnknown: { try { return Dynamic.InvokeMember(target, Name, args); } catch (RuntimeBinderException) { Dynamic.InvokeMemberAction(target, Name, args); return null; } } case InvocationKind.Invoke: return Dynamic.Invoke(target, args); case InvocationKind.InvokeAction: Dynamic.InvokeAction(target, args); return null; case InvocationKind.InvokeUnknown: { try { return Dynamic.Invoke(target, args); } catch (RuntimeBinderException) { Dynamic.InvokeAction(target, args); return null; } } case InvocationKind.AddAssign: Dynamic.InvokeAddAssignMember(target, Name.Name, args.FirstOrDefault()); return null; case InvocationKind.SubtractAssign: Dynamic.InvokeSubtractAssignMember(target, Name.Name, args.FirstOrDefault()); return null; case InvocationKind.IsEvent: return Dynamic.InvokeIsEvent(target, Name.Name); default: throw new InvalidOperationException("Unknown Invocation Kind: " + Kind); } } /// /// Invokes the invocation on specified target. /// /// The target. /// public virtual object InvokeWithStoredArgs(object target) { return Invoke(target, Args); } } } ================================================ FILE: Dynamitey/InvokeArg.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dynamitey { /// /// Use for Named arguments passed to InvokeMethods /// public class InvokeArg { /// /// Performs an explicit conversion from to . /// /// The pair. /// The result of the conversion. public static explicit operator InvokeArg(KeyValuePair pair) { return new InvokeArg(pair.Key,pair.Value); } /// /// Create Function can set to variable to make cleaner syntax; /// public static readonly Func Create = Return.Arguments((n, v) => new InvokeArg(n, v)); /// /// Initializes a new instance of the class. /// /// The name. /// The value. public InvokeArg(string name, object value) { Name = name; Value = value; } /// /// Gets or sets the argument name. /// /// The name. public string Name { get; private set; } /// /// Gets or sets the argument value. /// /// The value. public object Value { get; private set; } } /// /// InvokeArg that makes it easier to Cast from any IDictionaryValue /// /// public class InvokeArg : InvokeArg { /// /// Initializes a new instance of the class. /// /// The name. /// The value. public InvokeArg(string name, object value):base(name,value){} /// /// Performs an explicit conversion from to . /// /// The pair. /// The result of the conversion. public static explicit operator InvokeArg(KeyValuePair pair) { return new InvokeArg(pair.Key, pair.Value); } } } ================================================ FILE: Dynamitey/InvokeContext.cs ================================================ // // Copyright 2011 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dynamitey { /// /// Specific version of InvokeContext which declares a type to be used to invoke static methods. /// public class StaticContext:InvokeContext { /// /// Performs an explicit conversion from to . /// /// The type. /// The result of the conversion. public static explicit operator StaticContext(Type type) { return new StaticContext(type); } /// /// Initializes a new instance of the class. /// /// The target. public StaticContext(Type target) : base(target, true, null) { } } /// /// Object that stores a context with a target for dynamic invocation /// public class InvokeContext { /// /// Create Function can set to variable to make cleaner syntax; /// public static readonly Func CreateContext = Return.Arguments((t, c) => new InvokeContext(t, c)); /// /// Create Function can set to variable to make cleaner syntax; /// public static readonly Func CreateStatic = Return.Arguments((t) => new InvokeContext(t, true, null)); /// /// Create Function can set to variable to make cleaner syntax; /// public static readonly Func CreateStaticWithContext = Return.Arguments((t, c) => new InvokeContext(t, true, c)); /// /// Gets or sets the target. /// /// The target. public object Target { get; protected set; } /// /// Gets or sets the context. /// /// The context. public Type Context { get; protected set; } /// /// Gets or sets a value indicating whether [static context]. /// /// true if [static context]; otherwise, false. public bool StaticContext { get; protected set; } /// /// Initializes a new instance of the class. /// /// The target. /// if set to true [static context]. /// The context. public InvokeContext(Type target, bool staticContext, object context) { if (context != null && !(context is Type)) { context = context.GetType(); } Target = target; Context = ((Type)context) ?? target; StaticContext = staticContext; } /// /// Initializes a new instance of the class. /// /// The target. /// The context. public InvokeContext(object target, object context) { this.Target = target; if (context != null && !(context is Type)) { context = context.GetType(); } Context = (Type)context; } } } ================================================ FILE: Dynamitey/InvokeMemberName.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dynamitey { /// /// String or InvokeMemberName /// public abstract class String_OR_InvokeMemberName { /// /// Performs an implicit conversion from to . /// /// The name. /// The result of the conversion. public static implicit operator String_OR_InvokeMemberName(string name) { return new InvokeMemberName(name, null); } /// /// Gets the name. /// /// The name. public string Name { get; protected set; } /// /// Gets the generic args. /// /// The generic args. public Type[] GenericArgs { get; protected set; } /// /// Gets or sets a value indicating whether this member is special name. /// /// /// true if this instance is special name; otherwise, false. /// public bool IsSpecialName { get; protected set; } } /// /// Name of Member with associated Generic parameters /// public sealed class InvokeMemberName:String_OR_InvokeMemberName { /// /// Create Function can set to variable to make cleaner syntax; /// public static readonly Func Create = Return.Arguments((n, a) => new InvokeMemberName(n, a)); /// /// Create Function can set to variable to make cleaner syntax; /// public static readonly Func CreateSpecialName = Return.Arguments(n => new InvokeMemberName(n, true)); /// /// Performs an implicit conversion from to . /// /// The name. /// The result of the conversion. public static implicit operator InvokeMemberName(string name) { return new InvokeMemberName(name,null); } /// /// Initializes a new instance of the class. /// /// The name. /// The generic args. public InvokeMemberName(string name, params Type[] genericArgs) { Name = name; GenericArgs = genericArgs; } /// /// Initializes a new instance of the class. /// /// The name. /// if set to true [is special name]. public InvokeMemberName(string name, bool isSpecialName) { Name = name; GenericArgs = new Type[]{}; IsSpecialName = isSpecialName; } /// /// Equalses the specified other. /// /// The other. /// public bool Equals(InvokeMemberName other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return EqualsHelper(other); } private bool EqualsHelper(InvokeMemberName other) { var tGenArgs = GenericArgs; var tOtherGenArgs = other.GenericArgs; return Equals(other.Name, Name) && !(other.IsSpecialName ^ IsSpecialName) && !(tOtherGenArgs == null ^ tGenArgs == null) && (tGenArgs == null || //Exclusive Or makes sure this doesn't happen // ReSharper disable AssignNullToNotNullAttribute tGenArgs.SequenceEqual(tOtherGenArgs)); // ReSharper restore AssignNullToNotNullAttribute } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (!(obj is InvokeMemberName)) return false; return EqualsHelper((InvokeMemberName) obj); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { unchecked { return (GenericArgs != null ? GenericArgs.Length.GetHashCode() * 397 : 0) ^ (Name.GetHashCode()); } } } } ================================================ FILE: Dynamitey/PartialApply.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Reflection; using Dynamitey.Internal.Optimization; namespace Dynamitey { /// /// Internal method for subsequent invocations of /// public class PartialApply : DynamicObject, IPartialApply { /// /// Pipes the argument into the function /// /// The argument. /// The function. /// public static dynamic operator |(dynamic argument, PartialApply function) { return ((dynamic)function)(argument); } /// /// Provides implementation for binary operations. Classes derived from the class can override this method to specify dynamic behavior for operations such as addition and multiplication. /// /// Provides information about the binary operation. The binder.Operation property returns an object. For example, for the sum = first + second statement, where first and second are derived from the DynamicObject class, binder.Operation returns ExpressionType.Add. /// The right operand for the binary operation. For example, for the sum = first + second statement, where first and second are derived from the DynamicObject class, is equal to second. /// The result of the binary operation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) { result = null; if (binder.Operation == ExpressionType.LeftShift) { result = ((dynamic)(this))(arg); return true; } return false; } /// /// Provides implementation for type conversion operations. Classes derived from the class can override this method to specify dynamic behavior for operations that convert an object from one type to another. /// /// Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted. For example, for the statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic), where sampleObject is an instance of the class derived from the class, binder.Type returns the type. The binder.Explicit property provides information about the kind of conversion that occurs. It returns true for explicit conversion and false for implicit conversion. /// The result of the type conversion operation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// public override bool TryConvert(ConvertBinder binder, out object result) { result = Dynamic.CoerceToDelegate(this, binder.Type); return result != null; } /// /// Initializes a new instance of the class. /// /// The target. /// The args. /// Name of the member. /// The total count. /// Kind of the invocation. public PartialApply(object target, object[] args, string memberName = null, int? totalCount = null, InvocationKind? invocationKind = null) { _target = target; _memberName = memberName; _invocationKind = invocationKind ?? (String.IsNullOrWhiteSpace(_memberName) ? InvocationKind.InvokeUnknown : InvocationKind.InvokeMemberUnknown); _totalArgCount = totalCount; _args = args; } private readonly int? _totalArgCount; private readonly object _target; private readonly string _memberName; private readonly object[] _args; private readonly InvocationKind _invocationKind; /// /// Gets the target. /// /// The target. public object Target => _target; /// /// Gets the name of the member. /// /// The name of the member. public string MemberName => _memberName; /// /// Gets the args. /// /// The args. public object[] Args => _args; /// /// Gets the total arg count. /// /// The total arg count. public int? TotalArgCount => _totalArgCount; /// /// Gets the kind of the invocation. /// /// The kind of the invocation. public InvocationKind InvocationKind => _invocationKind; private IDictionary _cacheableInvocation = new Dictionary(); #pragma warning disable 1734 /// /// Provides the implementation for operations that invoke an object. Classes derived from the class can override this method to specify dynamic behavior for operations such as invoking an object or a delegate. /// /// Provides information about the invoke operation. /// The arguments that are passed to the object during the invoke operation. For example, for the sampleObject(100) operation, where sampleObject is derived from the class, is equal to 100. /// The result of the object invocation. /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown. /// #pragma warning restore 1734 public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { var tNamedArgs = Util.NameArgsIfNecessary(binder.CallInfo, args); var tNewArgs = _args.Concat(tNamedArgs).ToArray(); if (_totalArgCount.HasValue && (_totalArgCount - Args.Length - args.Length > 0)) //Not Done currying { result = new PartialApply(Target, tNewArgs, MemberName, TotalArgCount, InvocationKind); return true; } var tInvokeDirect = String.IsNullOrWhiteSpace(_memberName); if (tInvokeDirect && binder.CallInfo.ArgumentNames.Count == 0 && _target is Delegate tDel) //Optimization for direct delegate calls { result = tDel.FastDynamicInvoke(tNewArgs); return true; } Invocation tInvocation; if (binder.CallInfo.ArgumentNames.Count == 0) //If no argument names we can cache the callsite { if (!_cacheableInvocation.TryGetValue(tNewArgs.Length, out var tCacheableInvocation)) { tCacheableInvocation = new CacheableInvocation(InvocationKind, _memberName, argCount: tNewArgs.Length, context: _target); _cacheableInvocation[tNewArgs.Length] = tCacheableInvocation; } tInvocation = tCacheableInvocation; } else { tInvocation = new Invocation(InvocationKind, _memberName); } result = tInvocation.Invoke(_target, tNewArgs); return true; } } /// /// Partial Application Proxy /// public interface IPartialApply { } } ================================================ FILE: Dynamitey/ThisFunctions.cs ================================================  // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Reflection; using Dynamitey.Internal.Compat; namespace Dynamitey { /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14,T15 arg15); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14,T15 arg15,T16 arg16); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14,T15 arg15); /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14,T15 arg15,T16 arg16); /// /// Extension method for Dealing with Special Delegate Type /// public static class ThisDelegate{ private static readonly HashSet _specialThisDels = new HashSet(){ typeof(ThisAction), typeof(ThisFunc<>), typeof(ThisAction<,>), typeof(ThisFunc<,>), typeof(ThisAction<,,>), typeof(ThisFunc<,,>), typeof(ThisAction<,,,>), typeof(ThisFunc<,,,>), typeof(ThisAction<,,,,>), typeof(ThisFunc<,,,,>), typeof(ThisAction<,,,,,>), typeof(ThisFunc<,,,,,>), typeof(ThisAction<,,,,,,>), typeof(ThisFunc<,,,,,,>), typeof(ThisAction<,,,,,,,>), typeof(ThisFunc<,,,,,,,>), typeof(ThisAction<,,,,,,,,>), typeof(ThisFunc<,,,,,,,,>), typeof(ThisAction<,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,>), typeof(ThisAction<,,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,,>), typeof(ThisAction<,,,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,,,>), typeof(ThisAction<,,,,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,,,,>), typeof(ThisAction<,,,,,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,,,,,>), typeof(ThisAction<,,,,,,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,,,,,,>), typeof(ThisAction<,,,,,,,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,,,,,,,>), typeof(ThisFunc<,,,,,,,,,,,,,,,,>), }; /// /// Determines whether [is special this delegate] [the specified del]. /// /// The del. /// /// true if [is special this delegate] [the specified del]; otherwise, false. /// public static bool IsSpecialThisDelegate(this Delegate del){ var tType =del.GetType(); if(!tType.GetTypeInfo().IsGenericType) return false; var tGenDel =del.GetType().GetGenericTypeDefinition(); var tReturn =_specialThisDels.Contains(tGenDel); return tReturn; } } } ================================================ FILE: Dynamitey/ThisFunctions.tt ================================================ <#@ template language="C#" #> <#@ output extension="cs" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> // Copyright 2010 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Reflection; using Dynamitey.Internal.Compat; namespace Dynamitey { /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction(dynamic @this); <# for(int i=1; i<=16; i++){ var tArgs = String.Concat(Enumerable.Range(2,i-1).Select(it=>String.Format(",in T{0}",it))); var tParms = String.Concat(Enumerable.Range(1,i).Select(it=>String.Format(",T{0} arg{0}",it))); #> /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate void ThisAction>(dynamic @this<#=tParms#>); <# } #> /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc(dynamic @this); <# for(int i=1; i<=16; i++){ var tArgs = String.Concat(Enumerable.Range(2,i-1).Select(it=>String.Format(",in T{0}",it))); var tParms = String.Concat(Enumerable.Range(1,i).Select(it=>String.Format(",T{0} arg{0}",it))); #> /// /// Special Delegate used to make impromptu object methods first parameter is this. /// public delegate TResult ThisFunc, out TResult>(dynamic @this<#=tParms#>); <# } #> /// /// Extension method for Dealing with Special Delegate Type /// public static class ThisDelegate{ private static readonly HashSet _specialThisDels = new HashSet(){ typeof(ThisAction), typeof(ThisFunc<>), <# for(int i=1; i<=16; i++){ var tCommas = String.Concat(Enumerable.Repeat(",",i)); #> <# if(i!=16){#> typeof(ThisAction<<#=tCommas#>>), <# } #> typeof(ThisFunc<<#=tCommas#>>), <# } #> }; /// /// Determines whether [is special this delegate] [the specified del]. /// /// The del. /// /// true if [is special this delegate] [the specified del]; otherwise, false. /// public static bool IsSpecialThisDelegate(this Delegate del){ var tType =del.GetType(); if(!tType.GetTypeInfo().IsGenericType) return false; var tGenDel =del.GetType().GetGenericTypeDefinition(); var tReturn =_specialThisDels.Contains(tGenDel); return tReturn; } } } ================================================ FILE: Dynamitey/Tupler.cs ================================================ // // Copyright 2013 Ekon Benefits // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using Dynamitey.DynamicObjects; using Dynamitey.Internal.Optimization; using Dynamitey.Internal.Compat; namespace Dynamitey { /// /// Dynamically Dealing with Tuples /// public static class Tupler { private class TuplerFix { private Tuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) { return new Tuple(item1, item2, item3, item4, item5, item6, item7, item8); } } private static TuplerFix TuplerHelper = new TuplerFix(); private static InvokeContext StaticTuple = InvokeContext.CreateStatic(typeof (Tuple)); /// /// Creates a Tuple with arg runtime types. /// /// The args. /// public static dynamic Create(params object[] args) { return args.ToTuple(); } /// /// Enumerable to tuple. /// /// The enumerable. /// public static dynamic ToTuple(this IEnumerable enumerable) { var items = enumerable as IEnumerable ?? enumerable.Cast(); if (items.Count() < 8) { return Dynamic.InvokeMember(StaticTuple, "Create", items.ToArray()); } return Dynamic.InvokeMember(TuplerHelper, "Create", items.Take(7).Concat(new object[] { items.Skip(7).ToTuple() }).ToArray()); } /// /// Firsts item of the specified tuple. /// /// The tuple. /// public static dynamic First(object tuple) { return Index(tuple, 0); } /// /// Second item of the specified tuple. /// /// The tuple. /// public static dynamic Second(object tuple) { return Index(tuple, 1); } /// /// Lasts item of the specified tuple. /// /// The tuple. /// public static dynamic Last(object tuple) { return Index(tuple, Size(tuple)-1); } /// /// Convert to list. /// /// The tuple. /// public static IList ToList(object tuple) { var list = new List(); HelperToList(list, tuple, safe:false); return list; } private static void HelperToList(List list, object tuple, bool safe) { if(HelperIsTuple(tuple, out var type, out var generic, out var size, safe)) { for (int i = 0; i < 7 && i < size; i++) { list.Add(HelperIndex(tuple,i,safe:true)); } if (size == 8) { HelperToList(list, (object)(((dynamic)tuple).Rest), true); } } } /// /// Gets value at the index of the specified tuple. /// /// The tuple. /// The index. /// /// index must be greater than or equalto 0;index public static dynamic Index(object tuple, int index) { return HelperIndex(tuple, index, false); } private static dynamic HelperIndex(object tuple, int index, bool safe) { var item = index + 1; if (!safe && item < 1) { throw new ArgumentException("index must be greater than or equalto 0", nameof(index)); } if (!safe && item > Size(tuple)) { throw new ArgumentException("index must be less than size", nameof(index)); } if (!safe && !IsTuple(tuple)) { return tuple; } if( item < 8) return InvokeHelper.TupleItem(tuple, item); object newtarget = ((dynamic) tuple).Rest; return HelperIndex(newtarget, item - 8, true); } /// /// Determines whether the specified target is a tuple. /// /// The target. /// /// true if the specified target is tuple; otherwise, false. /// public static bool IsTuple(object target) { return HelperIsTuple(target, out var type, out var genericType, out var size, false); } private static bool HelperIsTuple(object target, out Type type, out Type genericeType, out int size, bool safe) { genericeType = typeof(object); size = 1; type = null; if (target == null) return false; type = target as Type ?? target.GetType(); if (safe || type.GetTypeInfo().IsGenericType) { genericeType = type.GetGenericTypeDefinition(); } return InvokeHelper.TupleArgs.TryGetValue(genericeType, out size); } /// /// Gets the size of the tuple /// /// The tuple. /// public static int Size(object tuple) { return HelperSize(tuple, false); } private static int HelperSize(object tuple, bool safe) { if (HelperIsTuple(tuple, out var type, out var genericType, out var size, safe)) { if (size == 8) { var lasttype = type.GetTypeInfo().GetGenericArguments()[7]; size = size + HelperSize(lasttype, true) - 1; } } return size; } } } ================================================ FILE: Dynamitey.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.34202.233 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{691EBA79-CAA4-4670-BC8B-4537F990ADBF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{C33F07DB-7ACB-4081-92C2-BB739CB605C0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SupportLibrary", "SupportLibrary\SupportLibrary.csproj", "{18E19833-D47E-4A7F-AE64-31E28FEF8728}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dynamitey", "Dynamitey\Dynamitey.csproj", "{8902AFBA-4ACA-4880-B606-ADEC6BB21A1B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3535FA34-121F-4DEB-97C5-4A90E54AEE94}" ProjectSection(SolutionItems) = preProject Version.props = Version.props Readme.md = Readme.md EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C33F07DB-7ACB-4081-92C2-BB739CB605C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C33F07DB-7ACB-4081-92C2-BB739CB605C0}.Debug|Any CPU.Build.0 = Debug|Any CPU {C33F07DB-7ACB-4081-92C2-BB739CB605C0}.Release|Any CPU.ActiveCfg = Release|Any CPU {C33F07DB-7ACB-4081-92C2-BB739CB605C0}.Release|Any CPU.Build.0 = Release|Any CPU {18E19833-D47E-4A7F-AE64-31E28FEF8728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {18E19833-D47E-4A7F-AE64-31E28FEF8728}.Debug|Any CPU.Build.0 = Debug|Any CPU {18E19833-D47E-4A7F-AE64-31E28FEF8728}.Release|Any CPU.ActiveCfg = Release|Any CPU {18E19833-D47E-4A7F-AE64-31E28FEF8728}.Release|Any CPU.Build.0 = Release|Any CPU {8902AFBA-4ACA-4880-B606-ADEC6BB21A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8902AFBA-4ACA-4880-B606-ADEC6BB21A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {8902AFBA-4ACA-4880-B606-ADEC6BB21A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {8902AFBA-4ACA-4880-B606-ADEC6BB21A1B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {C33F07DB-7ACB-4081-92C2-BB739CB605C0} = {691EBA79-CAA4-4670-BC8B-4537F990ADBF} {18E19833-D47E-4A7F-AE64-31E28FEF8728} = {691EBA79-CAA4-4670-BC8B-4537F990ADBF} EndGlobalSection EndGlobal ================================================ FILE: Dynamitey.sln.DotSettings ================================================  DB SL True <data><IncludeFilters /><ExcludeFilters /></data> <data /> True True True True True True ================================================ FILE: License.txt ================================================ Apache License, Version 2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: NuGet.config ================================================ ================================================ FILE: Readme.md ================================================ # Dynamitey (pronounced dyna-mighty) flexes DLR muscle to do meta-mazing things in .net Dynamitey is available Nuget [![NuGet](https://img.shields.io/nuget/dt/Dynamitey.svg)](https://www.nuget.org/packages/Dynamitey/) Framework | Platform | Status --------- | -------- | ------ All | Windows | [![Actions Status](https://github.com/ekonbenefits/dynamitey/actions/workflows/dotnet48.yml/badge.svg)](https://github.com/ekonbenefits/dynamitey/actions/workflows/dotnet48.yml) .NET Core | Linux/Mac | [![Actions Status](https://github.com/ekonbenefits/dynamitey/actions/workflows/dotnet.yml/badge.svg)](https://github.com/ekonbenefits/dynamitey/actions/workflows/dotnet.yml) Compiled For| --------| .Net Std 2.0 | .Net 4.0 | [Change Log](https://github.com/ekonbenefits/dynamitey/releases) Install with [Nuget](https://nuget.org/packages/Dynamitey/): ``` PM> Install-Package Dynamitey ``` # Meta-mazing Features - Easy Fast DLR based Reflection -- [oooo](https://github.com/ekonbenefits/dynamitey/wiki/UsageReallyLateBinding) - Clean syntax for using types from late bound libraries -- [ahhh](https://github.com/ekonbenefits/dynamitey/wiki/LateType) - Dynamic Currying -- [whaaa?](https://github.com/ekonbenefits/dynamitey/wiki/UsageCurry) - Manipulation of Tuples -- [wowzers](https://github.com/ekonbenefits/dynamitey/blob/master/Tests/TuplerTest.cs) - Inline Object Graph Intialization Syntax [whoa](https://github.com/ekonbenefits/dynamitey/wiki/UsageBuilder) - DynamicObject base types for many things -- [jenkies](https://github.com/ekonbenefits/dynamitey/wiki/UsageDynamic) - Extension to instance method conversion -- [o_O](https://github.com/ekonbenefits/dynamitey/blob/master/Tests/Linq.cs) ================================================ FILE: SupportLibrary/SupportLibrary.csproj ================================================  netstandard2.0 ================================================ FILE: SupportLibrary/SupportTypes.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using Dynamitey; namespace Dynamitey.SupportLibrary { public class TestEvent { public event EventHandler Event; public void OnEvent(object obj, EventArgs args) { if (Event != null) Event(obj, args); } } public static class TestFuncs { public static Func Plus3 { get { return x => x + 3; } } } public class PublicType { public static object InternalInstance => new InternalType(); public bool PrivateMethod(object param) { return param != null; } } internal class InternalType { public bool InternalMethod(object param) { return param != null; } } public interface IDynamicArg { dynamic ReturnIt(dynamic arg); bool Params(params dynamic[] args); } public class PocoNonDynamicArg { public int ReturnIt(int i) { return i; } public List ReturnIt(List i) { return i; } public bool Params(object fallback) { return false; } public bool Params(params int[] args) { return true; } } public static class StaticType { public static TReturn Create(int type) { return default(TReturn); } public static bool Test => true; public static int TestSet { get; set; } } public interface ISimpeleClassProps { string Prop1 { get; } long Prop2 { get; } Guid Prop3 { get; } } public interface IInheritProp : ISimpeleClassProps { PropPoco ReturnProp { get; set; } } public interface IPropPocoProp { PropPoco ReturnProp { get; set; } } public interface IEventCollisions { int Event { get; set; } } public interface IEvent { event EventHandler Event; void OnEvent(object obj, EventArgs args); } public class PocoEvent { public event EventHandler Event; public void OnEvent(object obj, EventArgs args) { if (Event != null) Event(obj, args); } } public class PocoOptConstructor { public string One { get; set; } public string Two { get; set; } public string Three { get; set; } public PocoOptConstructor(string one = "-1", string two = "-2", string three = "-3") { One = one; Two = two; Three = three; } } public enum TestEnum { None, One, Two } public interface IDynamicDict { int Test1 { get; } long Test2 { get; } TestEnum Test3 { get; } TestEnum Test4 { get; } dynamic TestD { get; } } public interface INonDynamicDict { int Test1 { get; } long Test2 { get; } TestEnum Test3 { get; } TestEnum Test4 { get; } IDictionary TestD { get; } } public interface ISimpleStringProperty { int Length { get; } } public interface IRobot { string Name { get; } } public class Robot { public string Name { get; set; } } public interface ISimpleStringMethod { bool StartsWith(string value); } public interface ISimpleStringMethodCollision { int StartsWith(string value); } public interface ISimpeleClassMeth { void Action1(); void Action2(bool value); string Action3(); } public interface ISimpeleClassMeth2 : ISimpeleClassMeth { string Action4(int arg); } public interface IGenericMeth { string Action(T arg); T Action2(T arg); } public interface IStringIntIndexer { string this[int index] { get; set; } } public interface IObjectStringIndexer { object this[string index] { get; set; } } public interface IGenericMethWithConstraints { string Action(T arg) where T : class; string Action2(T arg) where T : IComparable; } public interface IGenericType { string Funct(T arg); } public interface IGenericTypeConstraints where T : class { string Funct(T arg); } public interface IOverloadingMethod { string Func(int arg); string Func(object arg); } public class PropPoco { public string Prop1 { get; set; } public long Prop2 { get; set; } public Guid Prop3 { get; set; } public int Event { get; set; } } public struct PropStruct { public string Prop1 { get; set; } public long Prop2 { get; set; } public Guid Prop3 { get; set; } public int Event { get; set; } } public interface IVoidMethod { void Action(); } public class VoidMethodPoco { public void Action() { } } public class OverloadingMethPoco { public string Func(int arg) { return "int"; } public string Func(object arg) { return "object"; } public string Func(object arg, object arg2, object arg3, object arg4, object arg5, object arg6) { return "object 6"; } public string Func(object one = null, object two = null, object three = null) { return "object named"; } } /// /// Dynamic Delegates need to return object or void, first parameter should be a CallSite, second object, followed by the expected arguments /// public delegate object DynamicTryString(CallSite callsite, object target, out string result); public class MethOutPoco { public bool Func(out string result) { result = "success"; return true; } } public class Thing { } public interface IGenericTest { List GetThings(Guid test) where T : Thing; } public class OtherThing { List GetThings(Guid test) where T : Thing { return new List(); } } public class ForwardGenericMethodsTestClass { public string Value { get; set; } public T Create(int arg) where T : ForwardGenericMethodsTestClass, new() { return new T { Value = "test" + arg }; } } public class GenericMethOutPoco { public bool Func(out T result) { result = default(T); return true; } } public interface IGenericMethodOut { bool Func(out T result); } public interface IMethodOut2 { bool Func(out int result); } public class MethRefPoco { public bool Func(ref int result) { result = result + 2; return true; } } public class PocoAdder { public int Add(int x, int y) { return x + y; } } public class PocoDoubleProp : IInheritProp, IPropPocoProp, IEnumerable { public string Prop1 => throw new NotImplementedException(); public long Prop2 => throw new NotImplementedException(); public Guid Prop3 => throw new NotImplementedException(); public PropPoco ReturnProp { get => throw new NotImplementedException(); set => throw new NotImplementedException(); //lgtm [cs/unused-property-value] } PropPoco IPropPocoProp.ReturnProp { get => throw new NotImplementedException(); set => throw new NotImplementedException(); //lgtm [cs/unused-property-value] } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } } public class PocoCollection : IList { public IEnumerator GetEnumerator() { throw new NotImplementedException(); } public void CopyTo(Array array, int index) { throw new NotImplementedException(); } public int Count => throw new NotImplementedException(); public object SyncRoot => throw new NotImplementedException(); public bool IsSynchronized => throw new NotImplementedException(); public int Add(object value) { throw new NotImplementedException(); } public bool Contains(object value) { throw new NotImplementedException(); } public void Clear() { throw new NotImplementedException(); } public int IndexOf(object value) { throw new NotImplementedException(); } public void Insert(int index, object value) { throw new NotImplementedException(); } public void Remove(object value) { throw new NotImplementedException(); } public void RemoveAt(int index) { throw new NotImplementedException(); } public object this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public bool IsReadOnly => throw new NotImplementedException(); public bool IsFixedSize => throw new NotImplementedException(); } } ================================================ FILE: TestResult.xml ================================================ Performance :IEnumerable { TSource Aggregate(Func func); TAccumulate Aggregate(TAccumulate seed,Func func); TResult Aggregate(TAccumulate seed,Func func,Func resultSelector); Boolean All(Func predicate); Boolean Any(); Boolean Any(Func predicate); ILinq Append(TSource element); ILinq AsEnumerable(); Double Average(Func selector); Nullable Average(Func> selector); Double Average(Func selector); Nullable Average(Func> selector); Single Average(Func selector); Nullable Average(Func> selector); Double Average(Func selector); Nullable Average(Func> selector); Decimal Average(Func selector); Nullable Average(Func> selector); ILinq Cast(); ILinq Concat(IEnumerable second); Boolean Contains(TSource value); Boolean Contains(TSource value,IEqualityComparer comparer); Int32 Count(); Int32 Count(Func predicate); ILinq DefaultIfEmpty(); ILinq DefaultIfEmpty(TSource defaultValue); ILinq Distinct(); ILinq Distinct(IEqualityComparer comparer); TSource ElementAt(Int32 index); TSource ElementAtOrDefault(Int32 index); ILinq Except(IEnumerable second); ILinq Except(IEnumerable second,IEqualityComparer comparer); TSource First(); TSource First(Func predicate); TSource FirstOrDefault(); TSource FirstOrDefault(Func predicate); ILinq> GroupBy(Func keySelector); ILinq> GroupBy(Func keySelector,IEqualityComparer comparer); ILinq> GroupBy(Func keySelector,Func elementSelector); ILinq> GroupBy(Func keySelector,Func elementSelector,IEqualityComparer comparer); ILinq GroupBy(Func keySelector,Func,TResult> resultSelector); ILinq GroupBy(Func keySelector,Func elementSelector,Func,TResult> resultSelector); ILinq GroupBy(Func keySelector,Func,TResult> resultSelector,IEqualityComparer comparer); ILinq GroupBy(Func keySelector,Func elementSelector,Func,TResult> resultSelector,IEqualityComparer comparer); ILinq GroupJoin(IEnumerable inner,Func outerKeySelector,Func innerKeySelector,Func,TResult> resultSelector); ILinq GroupJoin(IEnumerable inner,Func outerKeySelector,Func innerKeySelector,Func,TResult> resultSelector,IEqualityComparer comparer); ILinq Intersect(IEnumerable second); ILinq Intersect(IEnumerable second,IEqualityComparer comparer); ILinq Join(IEnumerable inner,Func outerKeySelector,Func innerKeySelector,Func resultSelector); ILinq Join(IEnumerable inner,Func outerKeySelector,Func innerKeySelector,Func resultSelector,IEqualityComparer comparer); TSource Last(); TSource Last(Func predicate); TSource LastOrDefault(); TSource LastOrDefault(Func predicate); Int64 LongCount(); Int64 LongCount(Func predicate); TSource Max(); Int32 Max(Func selector); Nullable Max(Func> selector); Int64 Max(Func selector); Nullable Max(Func> selector); Single Max(Func selector); Nullable Max(Func> selector); Double Max(Func selector); Nullable Max(Func> selector); Decimal Max(Func selector); Nullable Max(Func> selector); TResult Max(Func selector); TSource Min(); Int32 Min(Func selector); Nullable Min(Func> selector); Int64 Min(Func selector); Nullable Min(Func> selector); Single Min(Func selector); Nullable Min(Func> selector); Double Min(Func selector); Nullable Min(Func> selector); Decimal Min(Func selector); Nullable Min(Func> selector); TResult Min(Func selector); ILinq OfType(); IOrderedLinq OrderBy(Func keySelector); IOrderedLinq OrderBy(Func keySelector,IComparer comparer); IOrderedLinq OrderByDescending(Func keySelector); IOrderedLinq OrderByDescending(Func keySelector,IComparer comparer); ILinq Prepend(TSource element); ILinq Reverse(); ILinq Select(Func selector); ILinq Select(Func selector); ILinq SelectMany(Func> selector); ILinq SelectMany(Func> selector); ILinq SelectMany(Func> collectionSelector,Func resultSelector); ILinq SelectMany(Func> collectionSelector,Func resultSelector); Boolean SequenceEqual(IEnumerable second); Boolean SequenceEqual(IEnumerable second,IEqualityComparer comparer); TSource Single(); TSource Single(Func predicate); TSource SingleOrDefault(); TSource SingleOrDefault(Func predicate); ILinq Skip(Int32 count); ILinq SkipLast(Int32 count); ILinq SkipWhile(Func predicate); ILinq SkipWhile(Func predicate); Int32 Sum(Func selector); Nullable Sum(Func> selector); Int64 Sum(Func selector); Nullable Sum(Func> selector); Single Sum(Func selector); Nullable Sum(Func> selector); Double Sum(Func selector); Nullable Sum(Func> selector); Decimal Sum(Func selector); Nullable Sum(Func> selector); ILinq Take(Int32 count); ILinq TakeLast(Int32 count); ILinq TakeWhile(Func predicate); ILinq TakeWhile(Func predicate); TSource[] ToArray(); Dictionary ToDictionary(Func keySelector); Dictionary ToDictionary(Func keySelector,IEqualityComparer comparer); Dictionary ToDictionary(Func keySelector,Func elementSelector); Dictionary ToDictionary(Func keySelector,Func elementSelector,IEqualityComparer comparer); HashSet ToHashSet(); HashSet ToHashSet(IEqualityComparer comparer); List ToList(); ILookup ToLookup(Func keySelector); ILookup ToLookup(Func keySelector,IEqualityComparer comparer); ILookup ToLookup(Func keySelector,Func elementSelector); ILookup ToLookup(Func keySelector,Func elementSelector,IEqualityComparer comparer); ILinq Union(IEnumerable second); ILinq Union(IEnumerable second,IEqualityComparer comparer); ILinq Where(Func predicate); ILinq Where(Func predicate); ILinq Zip(IEnumerable second,Func resultSelector); } public interface IOrderedLinq : ILinq, IOrderedEnumerable { IOrderedLinq ThenBy(Func keySelector); IOrderedLinq ThenBy(Func keySelector,IComparer comparer); IOrderedLinq ThenByDescending(Func keySelector); IOrderedLinq ThenByDescending(Func keySelector,IComparer comparer); } //Skipped Methods //Double Average(IEnumerable source); //Nullable Average(IEnumerable> source); //Double Average(IEnumerable source); //Nullable Average(IEnumerable> source); //Single Average(IEnumerable source); //Nullable Average(IEnumerable> source); //Double Average(IEnumerable source); //Nullable Average(IEnumerable> source); //Decimal Average(IEnumerable source); //Nullable Average(IEnumerable> source); //Int32 Max(IEnumerable source); //Nullable Max(IEnumerable> source); //Int64 Max(IEnumerable source); //Nullable Max(IEnumerable> source); //Double Max(IEnumerable source); //Nullable Max(IEnumerable> source); //Single Max(IEnumerable source); //Nullable Max(IEnumerable> source); //Decimal Max(IEnumerable source); //Nullable Max(IEnumerable> source); //Int32 Min(IEnumerable source); //Nullable Min(IEnumerable> source); //Int64 Min(IEnumerable source); //Nullable Min(IEnumerable> source); //Single Min(IEnumerable source); //Nullable Min(IEnumerable> source); //Double Min(IEnumerable source); //Nullable Min(IEnumerable> source); //Decimal Min(IEnumerable source); //Nullable Min(IEnumerable> source); //ILinq Range(Int32 start,Int32 count); //ILinq Repeat(TResult element,Int32 count); //Int32 Sum(IEnumerable source); //Nullable Sum(IEnumerable> source); //Int64 Sum(IEnumerable source); //Nullable Sum(IEnumerable> source); //Single Sum(IEnumerable source); //Nullable Sum(IEnumerable> source); //Double Sum(IEnumerable source); //Nullable Sum(IEnumerable> source); //Decimal Sum(IEnumerable source); //Nullable Sum(IEnumerable> source); ]]> ================================================ FILE: Tests/Curry.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Dynamitey.SupportLibrary; using NUnit.Framework; namespace Dynamitey.Tests { [TestFixture] public class Curry : Helper { [Test] public void TestBasicDelegateCurry() { Func tAdd = (x, y) => x + y; var tCurriedAdd4 = Dynamic.Curry(tAdd)(4); var tResult = tCurriedAdd4(6); Assert.AreEqual(10, tResult); } [Test] public void TestBasicNamedCurry() { Func tSub = (x, y) => x - y; var tCurriedSub7 = Dynamic.Curry(tSub)(arg2: 7); var tResult = tCurriedSub7(arg1: 10); Assert.AreEqual(3, tResult); } [Test] public void TestBasicConvertDelegateCurry() { Func tAdd = (x, y) => x + y; var tCurriedAdd4 = Dynamic.Curry(tAdd)("4"); var tCastToFunc = (Func)tCurriedAdd4; var tResult2 = tCastToFunc("10"); Assert.AreEqual("410", tResult2); } [Test] public void TestBasicConvertDelegateCurryReturnValueType() { Func tAdd = (x, y) => Int32.Parse(x) + Int32.Parse(y); var tCurriedAdd4 = Dynamic.Curry(tAdd)("4"); Func tCastToFunc = tCurriedAdd4; var tResult2 = tCastToFunc("10"); Assert.AreEqual(14, tResult2); } public delegate bool TestDeclaredDelagate(string value); [Test] public void TestBasicConvertNonGenericDelegate() { Func tContains = (x, y) => y.Contains(x); var tCurriedContains = Dynamic.Curry(tContains)("it"); TestDeclaredDelagate tCastToDel = tCurriedContains; var tResult = tCastToDel("bait"); Assert.AreEqual(true, tResult); } public delegate void TestRunDelagate(string value); [Test] public void TestBasicConvertNonGenericDelegateAction() { var tBool = false; Action tContains = (x, y) => tBool = y.Contains(x); var tCurriedContains = Dynamic.Curry(tContains)("it"); TestRunDelagate tCastToDel = tCurriedContains; tCastToDel("bait"); Assert.AreEqual(true, tBool); } [Test] public void TestBasicConvertDelegateCurryParamValueType() { Func tAdd = (x, y) => x + y; var tCurriedAdd4 = Dynamic.Curry(tAdd)(4); Func tCastToFunc = tCurriedAdd4; var tResult2 = tCastToFunc(10); Assert.AreEqual(14, tResult2); } [Test] public void TestBasicConvertMoreCurryParamValueType() { Func tAdd = (x, y, z) => x + y + z; Func> Curry1 = Dynamic.Curry(tAdd)(4); Func Curry2 = Curry1(6); int tResult = Curry2(10); Assert.AreEqual(20, tResult); } [Test] public void TestBasicConvertMoreMoreCurryParamValueType() { Func tAdd = (x, y, z, bbq) => x + y + z + bbq; Func>>> Curry0 = Dynamic.Curry(tAdd); var Curry1 = Curry0(4); var Curry2 = Curry1(5); var Curry3 = Curry2(6); var tResult = Curry3(20); Assert.AreEqual(35, tResult); } [Test] public void TestPococMethodCurry() { var tNewObj = new PocoAdder(); var tCurry = Dynamic.Curry(tNewObj).Add(4); var tResult = tCurry(10); Assert.AreEqual(14, tResult); //Test cached invocation; var tResult2 = tCurry(30); Assert.AreEqual(34, tResult2); } [Test] public void TestStaticMethodCurry() { var curry = Dynamic.Curry((StaticContext)typeof(string), 5).Format(); // curry method target include argument count curry = curry("Test {0}, {1}, {2}, {3}"); curry = curry("A"); curry = curry("B"); curry = curry("C"); string result = curry("D"); Assert.AreEqual("Test A, B, C, D", result); } [Test] public void TestStaticMethodLongCurry() { object curriedJoin = Dynamic.Curry((StaticContext)typeof(string), 51).Join(","); Func applyFunc = (result, each) => result(each.ToString()); string final = Enumerable.Range(1, 100) .Where(i => i % 2 == 0) .Aggregate(curriedJoin, applyFunc); Console.WriteLine(final); } [Test] public void TestStaticMethodLongCurry2() { var tFormat = Enumerable.Range(0, 100).Aggregate(new StringBuilder(), (result, each) => result.Append("{" + each + "}")).ToString(); dynamic curriedWrite = Dynamic.Curry(Console.Out, 101).WriteLine(tFormat); Func applyArgs = (result, each) => result(each.ToString()); Enumerable.Range(0, 100).Aggregate((object)curriedWrite, applyArgs); } [Test] public void TestDynamicMethodCurry() { var tNewObj = Build.NewObject(Add: Return.Arguments((x, y) => x + y)); var tCurry = Dynamic.Curry(tNewObj).Add(4); var tResult = tCurry(10); Assert.AreEqual(14, tResult); //Test cached invocation; var tResult2 = tCurry(30); Assert.AreEqual(34, tResult2); } [Test] public void UnboundedCurry() { var tNewObject = Dynamic.Curry(Build.NewObject); var tCurriedNewObject = tNewObject(One: 1); var tResult = tCurriedNewObject(Two: 2); Assert.AreEqual(1, tResult.One); Assert.AreEqual(2, tResult.Two); } [Test] public void UnboundedCurryCont() { var tNewObject = Dynamic.Curry(Build.NewObject); tNewObject = tNewObject(One: 1); tNewObject = Dynamic.Curry(tNewObject)(Two: 2); var tResult = tNewObject(Three: 3); Assert.AreEqual(1, tResult.One); Assert.AreEqual(2, tResult.Two); Assert.AreEqual(3, tResult.Three); } [Test] public void BoundedCurryCont() { var tNewObject = Dynamic.Curry(Build.NewObject, 3); tNewObject = tNewObject(One: 1); tNewObject = tNewObject(Two: 2); var tResult = tNewObject(Three: 3); Assert.AreEqual(1, tResult.One); Assert.AreEqual(2, tResult.Two); Assert.AreEqual(3, tResult.Three); } [Test] public void TestCurryNamedMethods() { Person adam = new Person(); dynamic jump = Dynamic.Curry(adam).Jump(); Assert.Throws(() => jump(cheer: "yay", height: (uint)3)); } private class Person { public void Jump(uint height, string cheer) { throw new NotImplementedException(); } } [Test] public void TestPococMethodPartialApply() { var tNewObj = new PocoAdder(); var tCurry = Dynamic.Curry(tNewObj).Add(4, 6); var tResult = tCurry(); Assert.AreEqual(10, tResult); } [Test] public void UnboundedPartialApply() { var tNewObject = Dynamic.Curry(Build.NewObject); tNewObject = tNewObject(One: 1, Two: 2); var tResult = tNewObject(Three: 3, Four: 4); Assert.AreEqual(1, tResult.One); Assert.AreEqual(2, tResult.Two); Assert.AreEqual(3, tResult.Three); Assert.AreEqual(4, tResult.Four); } [Test] public void BasicCurryTest() { Func adder = (x, y, z) => x + y + z; var curried = Dynamic.Curry(adder); Assert.AreEqual(6, curried(1, 2, 3)); Assert.AreEqual(6, curried(1, 2)(3)); Assert.AreEqual(6, curried(1)(2, 3)); Assert.AreEqual(6, curried(1)(2)(3)); } [Test] public void CurryLeftPipeTest() { Func adder = (x, y, z) => x + y + z; var curried = Dynamic.Curry(adder); Assert.That((object)(curried << "1" << "2" << "3"), Is.EqualTo("123")); } [Test] public void CurryRightPipeTest() { Func adder = (x, y, z) => x + y + z; var curried = Dynamic.Curry(adder); Assert.That((object) ("1" | ( "2" | ("3" | curried))), Is.EqualTo("321")); } } } ================================================ FILE: Tests/DynamicObjects.cs ================================================ using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using Dynamitey.SupportLibrary; using Microsoft.CSharp; using NUnit.Framework; namespace Dynamitey.Tests { [TestFixture] public class DynamicObjs : Helper { [Test] public void GetterAnonTest() { var tAnon = new {Prop1 = "Test", Prop2 = 42L, Prop3 = Guid.NewGuid()}; dynamic tTest = new DynamicObjects.Get(tAnon); Assert.AreEqual(tAnon.Prop1, tTest.Prop1); Assert.AreEqual(tAnon.Prop2, tTest.Prop2); Assert.AreEqual(tAnon.Prop3, tTest.Prop3); } [Test] public void GetterVoidTest() { var tPoco = new VoidMethodPoco(); dynamic tTest = new DynamicObjects.Get(tPoco); tTest.Action(); } [Test] public void GetterArrayTest() { var tArray = new int[] {1, 2, 3}; dynamic tTest = new DynamicObjects.Get(tArray); Dynamic.ApplyEquivalentType(tTest, typeof (IStringIntIndexer)); Assert.AreEqual(tArray[2].ToString(), tTest[2]); } [Test] public void GetterEventTest() { dynamic dynEvent = new DynamicObjects.Get(new PocoEvent()); Dynamic.ApplyEquivalentType(dynEvent, typeof (IEvent)); var tSet = false; EventHandler tActsLikeOnEvent = (obj, args) => tSet = true; dynEvent.Event += tActsLikeOnEvent; dynEvent.OnEvent(null, null); Assert.AreEqual(true, tSet); } [Test] public void GetterEventTest2() { dynamic dynEvent = new DynamicObjects.Get(new PocoEvent()); Dynamic.ApplyEquivalentType(dynEvent, typeof (IEvent)); var tSet = false; EventHandler tActsLikeOnEvent = (obj, args) => tSet = true; dynEvent.Event += tActsLikeOnEvent; dynEvent.Event -= tActsLikeOnEvent; dynEvent.OnEvent(null, null); Assert.AreEqual(false, tSet); } [Test] public void GetterDynamicTest() { dynamic tNew = new ExpandoObject(); tNew.Prop1 = "Test"; tNew.Prop2 = 42L; tNew.Prop3 = Guid.NewGuid(); dynamic tTest = new DynamicObjects.Get(tNew); Assert.AreEqual(tNew.Prop1, tTest.Prop1); Assert.AreEqual(tNew.Prop2, tTest.Prop2); Assert.AreEqual(tNew.Prop3, tTest.Prop3); } public class TestForwarder : Dynamitey.DynamicObjects.BaseForwarder { public TestForwarder(object target) : base(target) { } } [Test] public void ForwardAnonTest() { var tAnon = new {Prop1 = "Test", Prop2 = 42L, Prop3 = Guid.NewGuid()}; dynamic tTest = new TestForwarder(tAnon); Assert.AreEqual(tAnon.Prop1, tTest.Prop1); Assert.AreEqual(tAnon.Prop2, tTest.Prop2); Assert.AreEqual(tAnon.Prop3, tTest.Prop3); } [Test] public void ForwardVoidTest() { var tPoco = new VoidMethodPoco(); dynamic tTest = new TestForwarder(tPoco); tTest.Action(); } [Test] public void ForwardGenericMethodsTest() { dynamic tNew = new ForwardGenericMethodsTestClass(); dynamic tFwd = new TestForwarder(tNew); Assert.AreEqual("test99", tFwd.Create(99).Value); } [Test] public void ForwardDynamicTest() { dynamic tNew = new ExpandoObject(); tNew.Prop1 = "Test"; tNew.Prop2 = 42L; tNew.Prop3 = Guid.NewGuid(); dynamic tTest = new TestForwarder(tNew); Assert.AreEqual(tNew.Prop1, tTest.Prop1); Assert.AreEqual(tNew.Prop2, tTest.Prop2); Assert.AreEqual(tNew.Prop3, tTest.Prop3); } [Test] public void DictionaryMethodsTest() { dynamic tNew = new DynamicObjects.Dictionary(); tNew.Action1 = new Action(Assert.Fail); tNew.Action2 = new Action(Assert.IsFalse); tNew.Action3 = new Func(() => "test"); tNew.Action4 = new Func(arg => "test" + arg); Assert.That(() => tNew.Action1(), Throws.InstanceOf()); Assert.That(() => tNew.Action2(true), Throws.InstanceOf()); Assert.That((object)tNew.Action3(), Is.EqualTo("test")); Assert.That((object)tNew.Action4(4), Is.EqualTo("test4")); } [Test] public void ForwardMethodsTest() { dynamic tNew = new DynamicObjects.Dictionary(); tNew.Action1 = new Action(Assert.Fail); tNew.Action2 = new Action(Assert.IsFalse); tNew.Action3 = new Func(() => "test"); tNew.Action4 = new Func(arg => "test" + arg); dynamic tFwd = new TestForwarder(tNew); Assert.That(() => tFwd.Action1(), Throws.InstanceOf()); Assert.That(() => tFwd.Action2(true), Throws.InstanceOf()); Assert.That((object)tFwd.Action3(), Is.EqualTo("test")); Assert.That((object)tFwd.Action4(4), Is.EqualTo("test4")); } [Test] public void DictionaryMethodsOutTest() { dynamic tNew = new DynamicObjects.Dictionary(); tNew.Func = new DynamicTryString(TestOut); Assert.AreEqual(true, tNew.Func(null, "Test", out string tOut)); Assert.AreEqual("Test", tOut); Assert.AreEqual(false, tNew.Func(null, 1, out string tOut2)); Assert.AreEqual(null, tOut2); } private static object TestOut(CallSite dummy, object @in, out string @out) { @out = @in as string; return @out != null; } [Test] public void DictionaryMethodsTestWithPropertyAccess() { dynamic tNew = new DynamicObjects.Dictionary(); tNew.PropCat = "Cat-"; tNew.Action1 = new Action(Assert.Fail); tNew.Action2 = new Action(Assert.IsFalse); tNew.Action3 = new ThisFunc(@this => @this.PropCat + "test"); Assert.That(() => tNew.Action1(), Throws.InstanceOf()); Assert.That(() => tNew.Action2(true), Throws.InstanceOf()); Assert.AreEqual("Cat-test", tNew.Action3()); } [Test] public void DictionaryNullMethodsTest() { dynamic tNew = new DynamicObjects.Dictionary(); Dynamic.ApplyEquivalentType(tNew, typeof (ISimpleStringMethod)); Assert.That((object)tNew.StartsWith("Te"), Is.False); } [Test] public void DynamicDictionaryWrappedTest() { var tDictionary = new Dictionary { {"Test1", 1}, {"Test2", 2}, { "TestD", new Dictionary() { {"TestA", "A"}, {"TestB", "B"} } } }; dynamic tNew = new DynamicObjects.Dictionary(tDictionary); Assert.AreEqual(1, tNew.Test1); Assert.AreEqual(2, tNew.Test2); Assert.AreEqual("A", tNew.TestD.TestA); Assert.AreEqual("B", tNew.TestD.TestB); } [Test] public void InterfaceDictionaryWrappedTest() { var tDictionary = new Dictionary { {"Test1", 1}, {"Test2", 2L}, {"Test3", 1}, {"Test4", "Two"}, { "TestD", new Dictionary() { {"TestA", "A"}, {"TestB", "B"} } } }; dynamic tDynamic = new DynamicObjects.Dictionary(tDictionary); dynamic tNotDynamic = new DynamicObjects.Dictionary(tDictionary); Dynamic.ApplyEquivalentType(tDynamic, typeof (IDynamicDict)); Dynamic.ApplyEquivalentType(tNotDynamic, typeof (INonDynamicDict)); Assert.AreEqual(tDynamic, tNotDynamic); Assert.AreEqual(1, tDynamic.Test1); Assert.AreEqual(2L, tDynamic.Test2); Assert.AreEqual(TestEnum.One, tDynamic.Test3); Assert.AreEqual(TestEnum.Two, tDynamic.Test4); Assert.AreEqual("A", tDynamic.TestD.TestA); Assert.AreEqual("B", tDynamic.TestD.TestB); Assert.AreEqual(1, tNotDynamic.Test1); Assert.AreEqual(2L, tNotDynamic.Test2); Assert.AreEqual(TestEnum.One, tNotDynamic.Test3); Assert.AreEqual(TestEnum.Two, tNotDynamic.Test4); Assert.AreEqual(typeof (Dictionary), tNotDynamic.TestD.GetType()); Assert.AreEqual(typeof (DynamicObjects.Dictionary), tDynamic.TestD.GetType()); } [Test] public void DynamicObjectEqualsTest() { var tDictionary = new Dictionary { {"Test1", 1}, {"Test2", 2}, { "TestD", new Dictionary() { {"TestA", "A"}, {"TestB", "B"} } } }; dynamic tDynamic = new DynamicObjects.Dictionary(tDictionary); dynamic tNotDynamic = new DynamicObjects.Dictionary(tDictionary); Dynamic.ApplyEquivalentType(tDynamic, typeof (IDynamicDict)); Dynamic.ApplyEquivalentType(tNotDynamic, typeof (INonDynamicDict)); Assert.AreEqual(tDynamic, tNotDynamic); Assert.AreEqual(tDynamic, tDictionary); Assert.AreEqual(tNotDynamic, tDictionary); } [Test] public void DynamicAnnonymousWrapper() { var tData = new Dictionary {{1, "test"}}; var tDyn = DynamicObjects.Get.Create(new { Test1 = 1, Test2 = "2", IsGreaterThan5 = Return.Arguments(it => it > 5), ClearData = ReturnVoid.Arguments(() => tData.Clear()) }); Assert.AreEqual(1, tDyn.Test1); Assert.AreEqual("2", tDyn.Test2); Assert.AreEqual(true, tDyn.IsGreaterThan5(6)); Assert.AreEqual(false, tDyn.IsGreaterThan5(4)); Assert.AreEqual(1, tData.Count); tDyn.ClearData(); Assert.AreEqual(0, tData.Count); } [Test] public void TestAnonInterface() { dynamic tInterface = new DynamicObjects.Get(new { CopyArray = ReturnVoid.Arguments( (ar, i) => Enumerable.Range(1, 10)), Count = 10, IsSynchronized = false, SyncRoot = this, GetEnumerator = Return.Arguments( () => Enumerable.Range(1, 10).GetEnumerator()) }); Dynamic.ApplyEquivalentType(tInterface, typeof (ICollection), typeof (IEnumerable)); Assert.AreEqual(10, tInterface.Count); Assert.AreEqual(false, tInterface.IsSynchronized); Assert.AreEqual(this, tInterface.SyncRoot); Assert.That((object)tInterface.GetEnumerator(), Is.InstanceOf()); } [Test] public void TestBuilder() { var New = Builder.New(); var tExpando = New.Object( Test: "test1", Test2: "Test 2nd" ); Assert.AreEqual("test1", tExpando.Test); Assert.AreEqual("Test 2nd", tExpando.Test2); dynamic NewD = new DynamicObjects.Builder(); var tExpandoNamedTest = NewD.Robot( LeftArm: "Rise", RightArm: "Clamp" ); Assert.AreEqual("Rise", tExpandoNamedTest.LeftArm); Assert.AreEqual("Clamp", tExpandoNamedTest.RightArm); } [Test] public void TestSetupOtherTypes() { var New = Builder.New().Setup( Expando: typeof (ExpandoObject), Dict: typeof (DynamicObjects.Dictionary) ); var tExpando = New.Expando( LeftArm: "Rise", RightArm: "Clamp" ); var tDict = New.Dict( LeftArm: "RiseD", RightArm: "ClampD" ); Assert.AreEqual("Rise", tExpando.LeftArm); Assert.AreEqual("Clamp", tExpando.RightArm); Assert.AreEqual(typeof (ExpandoObject), tExpando.GetType()); Assert.AreEqual("RiseD", tDict.LeftArm); Assert.AreEqual("ClampD", tDict.RightArm); Assert.AreEqual(typeof (DynamicObjects.Dictionary), tDict.GetType()); } [Test] //This test data is modified from MS-PL Clay project http://clay.codeplex.com public void TestClayFactorySyntax() { dynamic New = Builder.New(); { var person = New.Person(); person.FirstName = "Louis"; person.LastName = "Dejardin"; Assert.AreEqual("Louis", person.FirstName); Assert.AreEqual("Dejardin", person.LastName); } { var person = New.Person(); person["FirstName"] = "Louis"; person["LastName"] = "Dejardin"; Assert.AreEqual("Louis", person.FirstName); Assert.AreEqual("Dejardin", person.LastName); } { var person = New.Person( FirstName: "Bertrand", LastName: "Le Roy" ).Aliases("bleroy", "boudin"); Assert.AreEqual("Bertrand", person.FirstName); Assert.AreEqual("Le Roy", person.LastName); Assert.AreEqual("boudin", person.Aliases[1]); } { var person = New.Person() .FirstName("Louis") .LastName("Dejardin") .Aliases(new[] {"Lou"}); Assert.AreEqual(person.FirstName, "Louis"); Assert.AreEqual(person.Aliases[0], "Lou"); } { var person = New.Person(new { FirstName = "Louis", LastName = "Dejardin" }); Assert.AreEqual(person.FirstName, "Louis"); Assert.AreEqual(person.LastName, "Dejardin"); } } [Test] //This test data is modified from MS-PL Clay project http://clay.codeplex.com public void TestFactoryListSyntax() { dynamic New = Builder.New(); //Test using Clay Syntax var people = New.Array( New.Person().FirstName("Louis").LastName("Dejardin"), New.Person().FirstName("Bertrand").LastName("Le Roy") ); Assert.AreEqual("Dejardin", people[0].LastName); Assert.AreEqual("Le Roy", people[1].LastName); var people2 = new DynamicObjects.List() { New.Robot(Name: "Bender"), New.Robot(Name: "RobotDevil") }; Assert.AreEqual("Bender", people2[0].Name); Assert.AreEqual("RobotDevil", people2[1].Name); } [Test] public void TestQuicListSyntax() { var tList = Build.NewList("test", "one", "two"); Assert.AreEqual("one", tList[1]); var tList2 = Build.NewList("test", "one", "two", "three"); Assert.AreEqual("three", tList2[3]); } [Test] public void TestRecorder() { dynamic New = Builder.New(); DynamicObjects.Recorder tRecording = New.Watson(Test: "One", Test2: 2, NameLast: "Watson"); dynamic tVar = tRecording.ReplayOn(new ExpandoObject()); Assert.AreEqual("One", tVar.Test); Assert.AreEqual(2, tVar.Test2); Assert.AreEqual("Watson", tVar.NameLast); } #if NETFRAMEWORK [Test] public void TestCodeDomLateTypeBind() { // http://stackoverflow.com/questions/16918612/dynamically-use-runtime-compiled-assemlby/16920438#16920438 string code = @" namespace CodeInjection { public static class DynConcatenateString { public static string Concatenate(string s1, string s2){ return s1 + "" ! "" + s2; } } }"; var codeProvider = new CSharpCodeProvider(); var parameters = new CompilerParameters {GenerateExecutable = false, GenerateInMemory = true}; CompilerResults cr = codeProvider.CompileAssemblyFromSource(parameters,code); dynamic DynConcatenateString = new DynamicObjects.LateType(cr.CompiledAssembly, "CodeInjection.DynConcatenateString"); Assert.That("1 ! 2", Is.EqualTo(DynConcatenateString.Concatenate("1","2"))); } #endif [Test] public void TestLateLibrarybind() { dynamic tBigIntType = new DynamicObjects.LateType( "System.Numerics.BigInteger, System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); if (tBigIntType.IsAvailable) { var one = tBigIntType.@new(1); var two = tBigIntType.@new(2); Assert.IsFalse(one.IsEven); Assert.AreEqual(true, two.IsEven); var tParsed = tBigIntType.Parse("4"); Assert.AreEqual(true, tParsed.IsEven); } else { Assert.Fail("Big Int Didn't Load"); } } } } ================================================ FILE: Tests/ExpandoObjs.cs ================================================ using System.Dynamic; using NUnit.Framework; namespace Dynamitey.Tests { [TestFixture] public class ExpandoObjs : Helper { [Test] public void TestExpando() { var New = Builder.New(); var tExpando = New.Object( Test: "test1", Test2: "Test 2nd" ); var tExpandoNew = Expando.New( Test: "test1", Test2: "Test 2nd" ); Assert.AreEqual("test1", tExpandoNew.Test); Assert.AreEqual("Test 2nd", tExpandoNew.Test2); Assert.AreEqual(tExpando.Test, tExpandoNew.Test); Assert.AreEqual(tExpando.Test2, tExpandoNew.Test2); Assert.AreEqual(tExpando.GetType(), tExpandoNew.GetType()); } [Test] public void TestExpando2() { dynamic NewD = new DynamicObjects.Builder(); var tExpandoNamedTest = NewD.Robot( LeftArm: "Rise", RightArm: "Clamp" ); dynamic NewE = new Expando(); var tExpandoNamedTestShortcut = NewE.Robot( LeftArm: "Rise", RightArm: "Clamp" ); Assert.AreEqual("Rise", tExpandoNamedTestShortcut.LeftArm); Assert.AreEqual("Clamp", tExpandoNamedTestShortcut.RightArm); Assert.AreEqual(tExpandoNamedTest.LeftArm, tExpandoNamedTestShortcut.LeftArm); Assert.AreEqual(tExpandoNamedTest.RightArm, tExpandoNamedTestShortcut.RightArm); Assert.AreEqual(tExpandoNamedTest.GetType(), tExpandoNamedTestShortcut.GetType()); } } } ================================================ FILE: Tests/Helper.cs ================================================ using NUnit.Framework; namespace Dynamitey.Tests { #pragma warning disable CS0618 // Type or member is obsolete public class Helper:AssertionHelper #pragma warning restore CS0618 // Type or member is obsolete { } } ================================================ FILE: Tests/Impromptu.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NUnit.Framework; using Dynamitey; using Dynamitey.DynamicObjects; using Dynamitey.SupportLibrary; using ImpromptuInterface; using NUnit.Framework.Constraints; namespace Dynamitey.Tests { [TestFixture(Category = "Impromptu")] public class Impromptu:Helper { public static readonly dynamic Interfacing = Dynamic.Curry(new Func(it=>ImpromptuInterface.Impromptu.ActLike(it))); [Test] public void DictionaryInterfaceNullMethodsTest() { dynamic tNew = new DynamicObjects.Dictionary(); ISimpleStringMethod tActsLike = ImpromptuInterface.Impromptu.ActLike(tNew); Assert.AreEqual(false, tActsLike.StartsWith("Te")); } [Test] public void FauxTypeTest() { var testProp = new Dictionary(){ {"test", typeof(bool)} }; var propType = new PropretySpecType(testProp); var propMembers = propType.GetMemberNames(); Expect(propMembers, Contains("test")); var realType = new RealType(typeof(ISimpeleClassProps)); var realMembers = realType.GetMemberNames(); Expect(realMembers, Contains("Prop2")); var aggrType = new AggreType(propType, realType); var aggrMembers = aggrType.GetMemberNames(); Expect(aggrMembers, Contains("Prop2")); Expect(aggrMembers, Contains("test")); } [Test] public void PropertySpecTest() { var testProp = new Dictionary(){ {"test", typeof(bool)} }; var baseObj = new DynamicObjects.Dictionary(); var output = ImpromptuInterface.Impromptu.ActLikeProperties(baseObj,testProp); if (baseObj.TryTypeForName("test", out Type ot)) { Assert.AreEqual(typeof(bool), ot); } else { Assert.Fail("Could not find property spec for member"); } } [Test] public void InterfaceSpecTest() { var baseObj = new DynamicObjects.Dictionary(); var output = ImpromptuInterface.Impromptu.ActLike(baseObj); if (baseObj.TryTypeForName("Prop2", out Type ot)) { Assert.AreEqual(typeof(long), ot); } else { Assert.Fail("Could not find property spec for member"); } } [Test] public void DictionaryCurriedAcctlikeNullMethodsTest() { ISimpleStringMethod tActsLike = Interfacing << new DynamicObjects.Dictionary(); Assert.AreEqual(false, tActsLike.StartsWith("Te")); } public interface IBuilder { INest Nester(object props); INested Nester2(object props); [ImpromptuInterface.UseNamedArgument] INest Nester(string NameLevel1, INested Nested); INested Nester2([ImpromptuInterface.UseNamedArgument] string NameLevel2); } public interface INest { String NameLevel1 { get; set; } INested Nested { get; set; } } public interface INested { string NameLevel2 { get; } } [Test] public void TestBuilderActLikeAnon() { IBuilder New = Interfacing << Builder.New(); var tNest = New.Nester(new { NameLevel1 = "Lvl1", Nested = New.Nester2(new { NameLevel2 = "Lvl2" }) }); Assert.AreEqual("Lvl1", tNest.NameLevel1); Assert.AreEqual("Lvl2", tNest.Nested.NameLevel2); } [Test] public void TestBuilderActLikeNamed() { IBuilder New = ImpromptuInterface.Impromptu.ActLike(Builder.New()); var tNest = New.Nester( NameLevel1: "Lvl1", Nested: New.Nester2( NameLevel2: "Lvl2" ) ); Assert.AreEqual("Lvl1", tNest.NameLevel1); Assert.AreEqual("Lvl2", tNest.Nested.NameLevel2); } } } ================================================ FILE: Tests/Invoke.cs ================================================ using System; using System.Collections.Generic; using System.Drawing; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Xml.Linq; using Dynamitey.SupportLibrary; using Microsoft.CSharp.RuntimeBinder; using Moq; using NUnit.Framework; using System.Globalization; namespace Dynamitey.Tests { public class Invoke:Helper { [OneTimeTearDown] public void DestroyCaches() { Dynamic.ClearCaches(); } [Test] public void TestDynamicSet() { dynamic tExpando = new ExpandoObject(); var tSetValue = "1"; Dynamic.InvokeSet(tExpando, "Test", tSetValue); Assert.AreEqual(tSetValue, tExpando.Test); } [Test] public void TestPocoSet() { var tPoco = new PropPoco(); var tSetValue = "1"; Dynamic.InvokeSet(tPoco, "Prop1", tSetValue); Assert.AreEqual(tSetValue, tPoco.Prop1); } [Test] public void TestStructSet() { object tPoco = new PropStruct(); var tSetValue = "1"; Dynamic.InvokeSet(tPoco, "Prop1", tSetValue); Assert.AreEqual(tSetValue, ((PropStruct)tPoco).Prop1); } [Test] public void TestCacheableDyanmicSetAndPocoSetAndSetNull() { dynamic tExpando = new ExpandoObject(); var tSetValueD = "4"; var tCachedInvoke = new CacheableInvocation(InvocationKind.Set, "Prop1"); tCachedInvoke.Invoke((object)tExpando, tSetValueD); Assert.AreEqual(tSetValueD, tExpando.Prop1); var tPoco = new PropPoco(); var tSetValue = "1"; tCachedInvoke.Invoke(tPoco, tSetValue); Assert.AreEqual(tSetValue, tPoco.Prop1); String tSetValue2 = null; tCachedInvoke.Invoke(tPoco, tSetValue2); Assert.AreEqual(tSetValue2, tPoco.Prop1); } [Test] public void TestConvert() { var tEl = new XElement("Test", "45"); var tCast = Dynamic.InvokeConvert(tEl, typeof(int), @explicit: true); Assert.AreEqual(typeof(int), tCast.GetType()); Assert.AreEqual(45, tCast); } [Test] public void TestConvertCacheable() { var tEl = new XElement("Test", "45"); var tCacheInvoke = new CacheableInvocation(InvocationKind.Convert, convertType: typeof(int), convertExplicit: true); var tCast = tCacheInvoke.Invoke(tEl); Assert.AreEqual(typeof(int), tCast.GetType()); Assert.AreEqual(45, tCast); } [Test] public void TestConstruct() { var tCast = Dynamic.InvokeConstructor(typeof(List), new object[] { new string[] {"one", "two", "three"} }); Assert.AreEqual("two", tCast[1]); } [Test] public void TestCacheableConstruct() { var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor, argCount: 1); dynamic tCast = tCachedInvoke.Invoke(typeof(List), new object[] { new string[] {"one", "two", "three"} }); Assert.AreEqual("two", tCast[1]); } [Test] public void TestConstructOptional() { var argname = InvokeArg.Create; PocoOptConstructor tCast = Dynamic.InvokeConstructor(typeof(PocoOptConstructor), argname("three", "3")); Assert.AreEqual("-1", tCast.One); Assert.AreEqual("-2", tCast.Two); Assert.AreEqual("3", tCast.Three); } [Test] public void TestCacheableConstructOptional() { var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor, argCount: 1, argNames: new[] { "three" }); var tCast = (PocoOptConstructor)tCachedInvoke.Invoke(typeof(PocoOptConstructor), "3"); Assert.AreEqual("-1", tCast.One); Assert.AreEqual("-2", tCast.Two); Assert.AreEqual("3", tCast.Three); } [Test] public void TestOptionalArgumentActivationNoneAndCacheable() { Assert.Throws(() => Activator.CreateInstance()); var tList = Dynamic.InvokeConstructor(typeof(DynamicObjects.List)); Assert.AreEqual(typeof(DynamicObjects.List), tList.GetType()); var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor); var tList1 = tCachedInvoke.Invoke(typeof(DynamicObjects.List)); Assert.AreEqual(typeof(DynamicObjects.List), tList1.GetType()); } [Test] public void TestConstructValueType() { var tCast = Dynamic.InvokeConstructor(typeof(DateTime), 2009, 1, 20); Assert.AreEqual(20, tCast.Day); } [Test] public void TestCacheableConstructValueType() { var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor, argCount: 3); dynamic tCast = tCachedInvoke.Invoke(typeof(DateTime), 2009, 1, 20); Assert.AreEqual(20, tCast.Day); } [Test] public void TestConstructValueTypeJustDynamic() { dynamic day = 20; dynamic year = 2009; dynamic month = 1; var tCast = new DateTime(year, month, day); DateTime tDate = tCast; Assert.AreEqual(20, tDate.Day); } [Test] public void TestConstructprimativetype() { var tCast = Dynamic.InvokeConstructor(typeof(Int32)); Assert.AreEqual(default(Int32), tCast); } [Test] public void TestConstructDateTimeNoParams() { var tCast = Dynamic.InvokeConstructor(typeof(DateTime)); Assert.AreEqual(default(DateTime), tCast); } [Test] public void TestConstructOBjectNoParams() { var tCast = Dynamic.InvokeConstructor(typeof(object)); Assert.AreEqual(typeof(object), tCast.GetType()); } [Test] public void TestConstructNullableprimativetype() { var tCast = Dynamic.InvokeConstructor(typeof(Nullable)); Assert.AreEqual(null, tCast); } [Test] public void TestConstructGuid() { var tCast = Dynamic.InvokeConstructor(typeof(Guid)); Assert.AreEqual(default(Guid), tCast); } [Test] public void TestCacheablePrimativeDateTimeObjectNullableAndGuidNoParams() { var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor); dynamic tCast = tCachedInvoke.Invoke(typeof(Int32)); Assert.AreEqual(default(Int32), tCast); tCast = tCachedInvoke.Invoke(typeof(DateTime)); Assert.AreEqual(default(DateTime), tCast); tCast = tCachedInvoke.Invoke(typeof(List)); Assert.AreEqual(typeof(List), tCast.GetType()); tCast = tCachedInvoke.Invoke(typeof(object)); Assert.AreEqual(typeof(object), tCast.GetType()); tCast = tCachedInvoke.Invoke(typeof(Nullable)); Assert.AreEqual(null, tCast); tCast = tCachedInvoke.Invoke(typeof(Guid)); Assert.AreEqual(default(Guid), tCast); } [Test] public void TestStaticCall() { var @static = InvokeContext.CreateStatic; var generic = InvokeMemberName.Create; var tOut = Dynamic.InvokeMember(@static(typeof(StaticType)), generic("Create",new[]{typeof(bool)}), 1); Assert.AreEqual(false, tOut); } [Test] public void TestCacheableStaticCall() { var @static = InvokeContext.CreateStatic; var generic = InvokeMemberName.Create; var tCached = new CacheableInvocation(InvocationKind.InvokeMember, generic("Create",new[]{typeof(bool)}) , argCount: 1, context: @static(typeof(StaticType))); var tOut = tCached.Invoke(typeof(StaticType), 1); Assert.AreEqual(false, tOut); } private class TestClass { public static int StaticProperty { get; set; } } [Test] public void TestStaticPropertySetFollowedByGetTest() { var staticContext = InvokeContext.CreateStatic; Dynamic.InvokeSet(staticContext(typeof(TestClass)), "StaticProperty", 42); var tOut = Dynamic.InvokeGet(staticContext(typeof(TestClass)), "StaticProperty"); Assert.AreEqual(42, tOut); } [Test] public void TestImplicitConvert() { var tEl = 45; var tCast = Dynamic.InvokeConvert(tEl, typeof(long)); Assert.AreEqual(typeof(long), tCast.GetType()); } [Test] public void TestCoerceConverterColor() { var colorString = "PaleVioletRed"; var color =Dynamic.CoerceConvert(colorString, typeof (Color)); Assert.That((object)color,Is.TypeOf()); Assert.That((object)color, Is.EqualTo(Color.PaleVioletRed)); } [Test] public void TestCoerceConverterDBNULL() { var tEl = DBNull.Value; var tCast = Dynamic.CoerceConvert(tEl, typeof(long)); Assert.AreEqual(typeof(long), tCast.GetType()); var tCast2 = Dynamic.CoerceConvert(tEl, typeof(string)); Assert.AreEqual(null, tCast2); Assert.AreNotEqual(null, tEl); } [Test] public void TestCacheableImplicitConvert() { var tEl = 45; var tCachedInvoke = CacheableInvocation.CreateConvert(typeof(long)); var tCast = tCachedInvoke.Invoke(tEl); Assert.AreEqual(typeof(long), tCast.GetType()); } [Test] public void TestCacheableGet() { var tCached = new CacheableInvocation(InvocationKind.Get, "Prop1"); var tSetValue = "1"; var tAnon = new PropPoco { Prop1 = tSetValue }; var tOut = tCached.Invoke(tAnon); Assert.AreEqual(tSetValue, tOut); var tSetValue2 = "2"; tAnon = new PropPoco { Prop1 = tSetValue2 }; var tOut2 = tCached.Invoke(tAnon); Assert.AreEqual(tSetValue2, tOut2); } [Test] public void TestGetIndexer() { dynamic tSetValue = "1"; var tAnon = new[] { tSetValue, "2" }; string tOut = Dynamic.InvokeGetIndex(tAnon, 0); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestGetIndexerValue() { var tAnon = new int[] { 1, 2 }; int tOut = Dynamic.InvokeGetIndex(tAnon, 1); Assert.AreEqual(tAnon[1], tOut); } [Test] public void TestGetLengthArray() { var tAnon = new[] { "1", "2" }; int tOut = Dynamic.InvokeGet(tAnon, "Length"); Assert.AreEqual(2, tOut); } [Test] public void TestGetIndexerArray() { dynamic tSetValue = "1"; var tAnon = new List { tSetValue, "2" }; string tOut = Dynamic.InvokeGetIndex(tAnon, 0); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestCacheableIndexer() { var tStrings = new[] { "1", "2" }; var tCachedInvoke = new CacheableInvocation(InvocationKind.GetIndex, argCount: 1); var tOut = (string)tCachedInvoke.Invoke(tStrings, 0); Assert.AreEqual(tStrings[0], tOut); var tOut2 = (string)tCachedInvoke.Invoke(tStrings, 1); Assert.AreEqual(tStrings[1], tOut2); var tInts = new int[] { 3, 4 }; var tOut3 = (int)tCachedInvoke.Invoke(tInts, 0); Assert.AreEqual(tInts[0], tOut3); var tOut4 = (int)tCachedInvoke.Invoke(tInts, 1); Assert.AreEqual(tInts[1], tOut4); var tList = new List { "5", "6" }; var tOut5 = (string)tCachedInvoke.Invoke(tList, 0); Assert.AreEqual(tList[0], tOut5); var tOut6 = (string)tCachedInvoke.Invoke(tList, 0); Assert.AreEqual(tList[0], tOut6); } [Test] public void TestSetIndexer() { dynamic tSetValue = "3"; var tAnon = new List { "1", "2" }; Dynamic.InvokeSetIndex(tAnon, 0, tSetValue); Assert.AreEqual(tSetValue, tAnon[0]); } [Test] public void TestCacheableSetIndexer() { dynamic tSetValue = "3"; var tList = new List { "1", "2" }; var tCachedInvoke = new CacheableInvocation(InvocationKind.SetIndex, argCount: 2); tCachedInvoke.Invoke(tList, 0, tSetValue); Assert.AreEqual(tSetValue, tList[0]); } [Test] public void TestMethodDynamicPassAndGetValue() { dynamic tExpando = new ExpandoObject(); tExpando.Func = new Func(it => it.ToString()); var tValue = 1; var tOut = Dynamic.InvokeMember(tExpando, "Func", tValue); Assert.AreEqual(tValue.ToString(), tOut); } [Test] public void TestCacheableMethodDynamicPassAndGetValue() { dynamic tExpando = new ExpandoObject(); tExpando.Func = new Func(it => it.ToString()); var tValue = 1; var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Func", 1); var tOut = tCachedInvoke.Invoke((object)tExpando, tValue); Assert.AreEqual(tValue.ToString(), tOut); } [Test] public void TestMethodStaticOverloadingPassAndGetValue() { var tPoco = new OverloadingMethPoco(); var tValue = 1; var tOut = Dynamic.InvokeMember(tPoco, "Func", tValue); Assert.AreEqual("int", tOut); Assert.AreEqual("int", (object)tOut); //should still be int because this uses runtime type var tOut2 = Dynamic.InvokeMember(tPoco, "Func", 1m); Assert.AreEqual("object", tOut2); var tOut3 = Dynamic.InvokeMember(tPoco, "Func", new { Anon = 1 }); Assert.AreEqual("object", tOut3); } [Test] public void TestCachedMethodStaticOverloadingPassAndGetValue() { var tPoco = new OverloadingMethPoco(); var tValue = 1; var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Func", argCount: 1); var tOut = tCachedInvoke.Invoke(tPoco, tValue); Assert.AreEqual("int", tOut); Assert.AreEqual("int", (object)tOut); //should still be int because this uses runtime type var tOut2 = tCachedInvoke.Invoke(tPoco, 1m); Assert.AreEqual("object", tOut2); var tOut3 = tCachedInvoke.Invoke(tPoco, new { Anon = 1 }); Assert.AreEqual("object", tOut3); } [Test] public void TestMethodPocoOverloadingPassAndGetValueArg() { var tPoco = new OverloadingMethPoco(); var tValue = 1; var tOut = Dynamic.InvokeMember(tPoco, "Func", new InvokeArg("arg", tValue)); Assert.AreEqual("int", tOut); Assert.AreEqual("int", (object)tOut); //should still be int because this uses runtime type var tOut2 = Dynamic.InvokeMember(tPoco, "Func", 1m); Assert.AreEqual("object", tOut2); var tOut3 = Dynamic.InvokeMember(tPoco, "Func", new { Anon = 1 }); Assert.AreEqual("object", tOut3); } [Test] public void TestMethodPocoOverloadingPassAndGetValueArgOptional() { var tPoco = new OverloadingMethPoco(); var tValue = 1; var arg = InvokeArg.Create; var tOut = Dynamic.InvokeMember(tPoco, "Func", arg("two", tValue)); Assert.AreEqual("object named", tOut); Assert.AreEqual("object named", (object)tOut); } [Test] public void TestCacheableMethodPocoOverloadingPassAndGetValueArgOptional() { var tPoco = new OverloadingMethPoco(); var tValue = 1; var tCachedIvnocation = new CacheableInvocation(InvocationKind.InvokeMember, "Func", argCount: 1, argNames: new[] { "two" }); var tOut = tCachedIvnocation.Invoke(tPoco, tValue); Assert.AreEqual("object named", tOut); Assert.AreEqual("object named", (object)tOut); } [Test] public void TestCacheableMethodPocoOverloadingPassAndGetValueArgPostiionalOptional() { var tPoco = new OverloadingMethPoco(); var tValue1 = 1; var tValue2 = 2; var tCachedIvnocation = new CacheableInvocation(InvocationKind.InvokeMember, "Func", argCount: 2, argNames: new[] { "two" }); var tOut = tCachedIvnocation.Invoke(tPoco, tValue1, tValue2); Assert.AreEqual("object named", tOut); Assert.AreEqual("object named", (object)tOut); } [Test] public void TestMethodPocoOverloadingPass2AndGetValueArgOptional() { var tPoco = new OverloadingMethPoco(); var tValue = 1; var arg = InvokeArg.Create; var tOut = Dynamic.InvokeMember(tPoco, "Func", arg("two", tValue), arg("one", tValue)); Assert.AreEqual("object named", tOut); Assert.AreEqual("object named", (object)tOut); } [Test] public void TestMethodPocoOverloadingPassAndGetValueNull() { var tPoco = new OverloadingMethPoco(); var tValue = 1; var tOut = Dynamic.InvokeMember(tPoco, "Func", tValue); Assert.AreEqual("int", tOut); Assert.AreEqual("int", (object)tOut); //should still be int because this uses runtime type var tOut2 = Dynamic.InvokeMember(tPoco, "Func", 1m); Assert.AreEqual("object", tOut2); var tOut3 = Dynamic.InvokeMember(tPoco, "Func", null); Assert.AreEqual("object", tOut3); var tOut4 = Dynamic.InvokeMember(tPoco, "Func", null, null, "test", null, null, null); Assert.AreEqual("object 6", tOut4); var tOut5 = Dynamic.InvokeMember(tPoco, "Func", null, null, null, null, null, null); Assert.AreEqual("object 6", tOut5); } /// /// To dynamically invoke a method with out or ref parameters you need to know the signature /// [Test] public void TestOutMethod() { string tResult = String.Empty; var tPoco = new MethOutPoco(); var tName = "Func"; var tContext = GetType(); var tBinder = Binder.InvokeMember(CSharpBinderFlags.None, tName, null, tContext, new[] { CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.IsOut | CSharpArgumentInfoFlags.UseCompileTimeType, null) }); var tSite = Dynamic.CreateCallSite(tBinder, tName, tContext); tSite.Target.Invoke(tSite, tPoco, out tResult); Assert.AreEqual("success", tResult); } [Test] public void TestMethodDynamicPassVoid() { var tTest = "Wrong"; var tValue = "Correct"; dynamic tExpando = new ExpandoObject(); tExpando.Action = new Action(it => tTest = it); Dynamic.InvokeMemberAction(tExpando, "Action", tValue); Assert.AreEqual(tValue, tTest); } [Test] public void TestCacheableMethodDynamicPassVoid() { var tTest = "Wrong"; var tValue = "Correct"; dynamic tExpando = new ExpandoObject(); tExpando.Action = new Action(it => tTest = it); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMemberAction, "Action", argCount: 1); tCachedInvoke.Invoke((object)tExpando, tValue); Assert.AreEqual(tValue, tTest); } [Test] public void TestCacheableMethodDynamicUnknowns() { var tTest = "Wrong"; var tValue = "Correct"; dynamic tExpando = new ExpandoObject(); tExpando.Action = new Action(it => tTest = it); tExpando.Func = new Func(it => it); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMemberUnknown, "Action", argCount: 1); tCachedInvoke.Invoke((object)tExpando, tValue); Assert.AreEqual(tValue, tTest); var tCachedInvoke2 = new CacheableInvocation(InvocationKind.InvokeMemberUnknown, "Func", argCount: 1); var Test2 = tCachedInvoke2.Invoke((object)tExpando, tValue); Assert.AreEqual(tValue, Test2); } [Test] public void TestMethodPocoGetValue() { var tValue = 1; var tOut = Dynamic.InvokeMember(tValue, "ToString"); Assert.AreEqual(tValue.ToString(), tOut); } [Test] public void TestMethodPocoPassAndGetValue() { HelpTestPocoPassAndGetValue("Test", "Te"); HelpTestPocoPassAndGetValue("Test", "st"); } private void HelpTestPocoPassAndGetValue(string tValue, string tParam) { var tExpected = tValue.StartsWith(tParam); var tOut = Dynamic.InvokeMember(tValue, "StartsWith", tParam); Assert.AreEqual(tExpected, tOut); } [Test] public void TestGetDynamic() { var tSetValue = "1"; dynamic tExpando = new ExpandoObject(); tExpando.Test = tSetValue; var tOut = Dynamic.InvokeGet(tExpando, "Test"); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestGetDynamicChained() { var tSetValue = "1"; dynamic tExpando = new ExpandoObject(); tExpando.Test = new ExpandoObject(); tExpando.Test.Test2 = new ExpandoObject(); tExpando.Test.Test2.Test3 = tSetValue; var tOut = Dynamic.InvokeGetChain(tExpando, "Test.Test2.Test3"); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestGetDynamicChainedWithIndexes() { var tSetValue = "1"; dynamic tExpando = Build.NewObject( Test: Build.NewObject( Test2: Build.NewList( Build.NewObject(Test3: Build.NewObject(Test4: tSetValue)) ) ) ); var tOut = Dynamic.InvokeGetChain(tExpando, "Test.Test2[0].Test3['Test4']"); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestSetDynamicChained() { var tSetValue = "1"; dynamic tExpando = new ExpandoObject(); tExpando.Test = new ExpandoObject(); tExpando.Test.Test2 = new ExpandoObject(); Dynamic.InvokeSetChain(tExpando, "Test.Test2.Test3", tSetValue); Assert.AreEqual(tSetValue, tExpando.Test.Test2.Test3); } [Test] public void TestSetDynamicChainedWithInexes() { var tSetValue = "1"; dynamic tExpando = Build.NewObject( Test: Build.NewObject( Test2: Build.NewList( Build.NewObject(Test3: Build.NewObject()) ) ) ); var tOut = Dynamic.InvokeSetChain(tExpando, "Test.Test2[0].Test3['Test4']", tSetValue); Assert.AreEqual(tSetValue, tExpando.Test.Test2[0].Test3["Test4"]); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestSetDynamicAllDict() { var tSetValue = "1"; dynamic tExpando = new ExpandoObject(); tExpando.Test = new ExpandoObject(); tExpando.Test.Test2 = new ExpandoObject(); Dynamic.InvokeSetAll(tExpando, new Dictionary { { "Test.Test2.Test3", tSetValue }, { "One", 1 }, { "Two", 2 } }); Dynamic.InvokeSetChain(tExpando, "Test.Test2.Test3", tSetValue); Assert.AreEqual(tSetValue, tExpando.Test.Test2.Test3); Assert.AreEqual(1, tExpando.One); Assert.AreEqual(2, tExpando.Two); } [Test] public void TestSetDynamicAllAnonymous() { dynamic tExpando = new ExpandoObject(); Dynamic.InvokeSetAll(tExpando, new { One = 1, Two = 2, Three = 3 }); Assert.AreEqual(1, tExpando.One); Assert.AreEqual(2, tExpando.Two); Assert.AreEqual(3, tExpando.Three); } [Test] public void TestSetDynamicAllNamed() { dynamic tExpando = new ExpandoObject(); Dynamic.InvokeSetAll(tExpando, One: 1, Two: 2, Three: 3); Assert.AreEqual(1, tExpando.One); Assert.AreEqual(2, tExpando.Two); Assert.AreEqual(3, tExpando.Three); } [Test] public void TestSetDynamicChainedOne() { var tSetValue = "1"; dynamic tExpando = new ExpandoObject(); Dynamic.InvokeSetChain(tExpando, "Test", tSetValue); Assert.AreEqual(tSetValue, tExpando.Test); } [Test] public void TestGetDynamicChainedOne() { var tSetValue = "1"; dynamic tExpando = new ExpandoObject(); tExpando.Test = tSetValue; var tOut = Dynamic.InvokeGetChain(tExpando, "Test"); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestCacheableGetDynamic() { var tSetValue = "1"; dynamic tExpando = new ExpandoObject(); tExpando.Test = tSetValue; var tCached = new CacheableInvocation(InvocationKind.Get, "Test"); var tOut = tCached.Invoke((object)tExpando); Assert.AreEqual(tSetValue, tOut); } [Test] public void TestStaticGet() { var @static = InvokeContext.CreateStatic; var tDate = Dynamic.InvokeGet(@static(typeof(DateTime)), "Today"); Assert.AreEqual(DateTime.Today, tDate); } [Test] public void TestCacheableStaticGet() { var @static = InvokeContext.CreateStatic; var tCached = new CacheableInvocation(InvocationKind.Get, "Today", context: @static(typeof(DateTime))); var tDate = tCached.Invoke(typeof(DateTime)); Assert.AreEqual(DateTime.Today, tDate); } [Test] public void TestStaticGet2() { var @static = InvokeContext.CreateStatic; var tVal = Dynamic.InvokeGet(@static(typeof(StaticType)), "Test"); Assert.AreEqual(true, tVal); } [Test] public void TestStaticGet3() { var tVal = Dynamic.InvokeGet((StaticContext)typeof(StaticType), "Test"); Assert.AreEqual(true, tVal); } [Test] public void TestStaticSet() { var @static = InvokeContext.CreateStatic; int tValue = 12; Dynamic.InvokeSet(@static(typeof(StaticType)), "TestSet", tValue); Assert.AreEqual(tValue, StaticType.TestSet); } [Test] public void TestCacheableStaticSet() { int tValue = 12; var @static = InvokeContext.CreateStatic; var tCachedInvoke = new CacheableInvocation(InvocationKind.Set, "TestSet", context: @static(typeof(StaticType))); tCachedInvoke.Invoke(typeof(StaticType), tValue); Assert.AreEqual(tValue, StaticType.TestSet); } [Test] public void TestStaticDateTimeMethod() { var @static = InvokeContext.CreateStatic; object tDateDyn = "01/20/2009"; var tDate = Dynamic.InvokeMember(@static(typeof(DateTime)), "Parse", tDateDyn, CultureInfo.GetCultureInfo("en-US")); Assert.AreEqual(new DateTime(2009, 1, 20), tDate); } [Test] public void TestCacheableStaticDateTimeMethod() { var @static = InvokeContext.CreateStatic; object tDateDyn = "01/20/2009"; var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Parse", 2, context: @static(typeof(DateTime))); var tDate = tCachedInvoke.Invoke(typeof(DateTime), tDateDyn,CultureInfo.GetCultureInfo("en-US")); Assert.AreEqual(new DateTime(2009, 1, 20), tDate); } [Test] public void TestIsEvent() { dynamic tPoco = new PocoEvent(); var tResult = Dynamic.InvokeIsEvent(tPoco, "Event"); Assert.AreEqual(true, tResult); } [Test] public void TestCacheableIsEventAndIsNotEvent() { object tPoco = new PocoEvent(); var tCachedInvoke = new CacheableInvocation(InvocationKind.IsEvent, "Event"); var tResult = tCachedInvoke.Invoke(tPoco); Assert.AreEqual(true, tResult); dynamic tDynamic = new DynamicObjects.Dictionary(); tDynamic.Event = null; var tResult2 = tCachedInvoke.Invoke((object)tDynamic); Assert.AreEqual(false, tResult2); } [Test] public void TestIsNotEvent() { dynamic tDynamic = new DynamicObjects.Dictionary(); tDynamic.Event = null; var tResult = Dynamic.InvokeIsEvent(tDynamic, "Event"); Assert.AreEqual(false, tResult); bool tTest = false; bool tTest2 = false; tDynamic.Event += new EventHandler((@object, args) => { tTest = true; }); tDynamic.Event += new EventHandler((@object, args) => { tTest2 = true; }); Assert.AreEqual(false, tTest); Assert.AreEqual(false, tTest2); tDynamic.Event(null, null); Assert.AreEqual(true, tTest); Assert.AreEqual(true, tTest2); } [Test] public void TestPocoAddAssign() { var tPoco = new PocoEvent(); bool tTest = false; Dynamic.InvokeAddAssignMember(tPoco, "Event", new EventHandler((@object, args) => { tTest = true; })); tPoco.OnEvent(null, null); Assert.AreEqual(true, tTest); var tPoco2 = new PropPoco() { Prop2 = 3 }; Dynamic.InvokeAddAssignMember(tPoco2, "Prop2", 4); Assert.AreEqual(7L, tPoco2.Prop2); } [Test] public void TestCacheablePocoAddAssign() { var tPoco = new PocoEvent(); bool tTest = false; var tCachedInvoke = new CacheableInvocation(InvocationKind.AddAssign, "Event"); tCachedInvoke.Invoke(tPoco, new EventHandler((@object, args) => { tTest = true; })); tPoco.OnEvent(null, null); Assert.AreEqual(true, tTest); var tPoco2 = new PropPoco() { Event = 3 }; tCachedInvoke.Invoke(tPoco2, 4); Assert.AreEqual(7L, tPoco2.Event); } [Test] public void TestPocoSubtractAssign() { var tPoco = new PocoEvent(); bool tTest = false; var tEvent = new EventHandler((@object, args) => { tTest = true; }); tPoco.Event += tEvent; Dynamic.InvokeSubtractAssignMember(tPoco, "Event", tEvent); tPoco.OnEvent(null, null); Assert.AreEqual(false, tTest); Dynamic.InvokeSubtractAssignMember(tPoco, "Event", tEvent);//Test Second Time var tPoco2 = new PropPoco() { Prop2 = 3 }; Dynamic.InvokeSubtractAssignMember(tPoco2, "Prop2", 4); Assert.AreEqual(-1L, tPoco2.Prop2); } [Test] public void TestCacheablePocoSubtractAssign() { var tPoco = new PocoEvent(); bool tTest = false; var tEvent = new EventHandler((@object, args) => { tTest = true; }); var tCachedInvoke = new CacheableInvocation(InvocationKind.SubtractAssign, "Event"); tPoco.Event += tEvent; tCachedInvoke.Invoke(tPoco, tEvent); tPoco.OnEvent(null, null); Assert.AreEqual(false, tTest); tCachedInvoke.Invoke(tPoco, tEvent);//Test Second Time var tPoco2 = new PropPoco() { Event = 3 }; tCachedInvoke.Invoke(tPoco2, 4); Assert.AreEqual(-1, tPoco2.Event); } [Test] public void TestDynamicAddAssign() { var tDyanmic = Build.NewObject(Prop2: 3, Event: null, OnEvent: new ThisAction((@this, obj, args) => @this.Event(obj, args))); bool tTest = false; Dynamic.InvokeAddAssignMember(tDyanmic, "Event", new EventHandler((@object, args) => { tTest = true; })); tDyanmic.OnEvent(null, null); Assert.AreEqual(true, tTest); Dynamic.InvokeAddAssignMember(tDyanmic, "Prop2", 4); Assert.AreEqual(7L, tDyanmic.Prop2); } [Test] public void TestCacheableDynamicAddAssign() { var tDyanmic = Build.NewObject(Prop2: 3, Event: null, OnEvent: new ThisAction((@this, obj, args) => @this.Event(obj, args))); var tDynamic2 = Build.NewObject(Event: 3); bool tTest = false; var tCachedInvoke = new CacheableInvocation(InvocationKind.AddAssign, "Event"); tCachedInvoke.Invoke((object)tDyanmic, new EventHandler((@object, args) => { tTest = true; })); tDyanmic.OnEvent(null, null); Assert.AreEqual(true, tTest); tCachedInvoke.Invoke((object)tDynamic2, 4); Assert.AreEqual(7, tDynamic2.Event); } [Test] public void TestDynamicSubtractAssign() { var tDyanmic = Build.NewObject(Prop2: 3, Event: null, OnEvent: new ThisAction((@this, obj, args) => @this.Event(obj, args))); bool tTest = false; var tEvent = new EventHandler((@object, args) => { tTest = true; }); tDyanmic.Event += tEvent; Dynamic.InvokeSubtractAssignMember(tDyanmic, "Event", tEvent); tDyanmic.OnEvent(null, null); Assert.AreEqual(false, tTest); Dynamic.InvokeSubtractAssignMember(tDyanmic, "Prop2", 4); Assert.AreEqual(-1L, tDyanmic.Prop2); } [Test] public void TestCacheableDynamicSubtractAssign() { var tDyanmic = Build.NewObject(Prop2: 3, Event: null, OnEvent: new ThisAction((@this, obj, args) => @this.Event(obj, args))); var tDynamic2 = Build.NewObject(Event: 3); bool tTest = false; var tEvent = new EventHandler((@object, args) => { tTest = true; }); var tCachedInvoke = new CacheableInvocation(InvocationKind.SubtractAssign, "Event"); tDyanmic.Event += tEvent; tCachedInvoke.Invoke((object)tDyanmic, tEvent); tDyanmic.OnEvent(null, null); Assert.AreEqual(false, tTest); tCachedInvoke.Invoke((object)tDynamic2, 4); Assert.AreEqual(-1, tDynamic2.Event); } [Test] public void TestDynamicMemberNamesExpando() { ExpandoObject tExpando = Build.NewObject(One: 1); Assert.AreEqual("One", Dynamic.GetMemberNames(tExpando, dynamicOnly: true).Single()); } [Test] public void TestDynamicMemberNamesImpromput() { DynamicObjects.Dictionary tDict = Build.NewObject(Two: 2); Assert.AreEqual("Two", Dynamic.GetMemberNames(tDict, dynamicOnly: true).Single()); } [Test] public void TestCachedInvocationEquality() { var tCachedIvnocation1 = new CacheableInvocation(InvocationKind.InvokeMember, "Func", argCount: 2, argNames: new[] { "two" }); var tCachedIvnocation2 = new CacheableInvocation(InvocationKind.InvokeMember, "Func", argCount: 2, argNames: new[] { "two" }); Assert.AreEqual(tCachedIvnocation1.GetHashCode(), tCachedIvnocation2.GetHashCode()); Assert.AreEqual(tCachedIvnocation1, tCachedIvnocation2); } private DynamicObject CreateMock(ExpressionType op) { var tMock = new Mock() { CallBase = true }; object result = It.IsAny(); tMock.Setup( s => s.TryBinaryOperation(It.Is(b => b.Operation == op), It.IsAny(), out result) ).Returns(true); return tMock.Object; } public class OperatorTestDynObject:DynamicObject{ ExpressionType _type; public OperatorTestDynObject(ExpressionType type){ _type = type; } public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result){ Assert.AreEqual(_type, binder.Operation); result = _type; return true; } public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result){ Assert.AreEqual(_type, binder.Operation); result = _type; return true; } } private void RunBinaryMockTests(ExpressionType type){ var mock = new OperatorTestDynObject(type); var dummy = new Object(); Dynamic.InvokeBinaryOperator(mock, type, dummy); } private void RunUnaryMockTests(ExpressionType type){ var mock = new OperatorTestDynObject(type); #pragma warning disable CS0618 // Type or member is obsolete Dynamic.InvokeUnaryOpartor(type,mock); #pragma warning restore CS0618 // Type or member is obsolete } [Test] public void TestInvokeAdd() { Assert.AreEqual(Dynamic.InvokeBinaryOperator(1, ExpressionType.Add, 2), 3); } [Test] public void TestInvokeBasicUnaryOperatorsDynamic() { RunUnaryMockTests(ExpressionType.Not); RunUnaryMockTests(ExpressionType.Negate); RunUnaryMockTests(ExpressionType.Increment); RunUnaryMockTests(ExpressionType.Decrement); } [Test] public void TestInvokeBasicBinaryOperatorsDynamic() { RunBinaryMockTests(ExpressionType.Add); RunBinaryMockTests(ExpressionType.Subtract); RunBinaryMockTests(ExpressionType.Divide); RunBinaryMockTests(ExpressionType.Multiply); RunBinaryMockTests(ExpressionType.Modulo); RunBinaryMockTests(ExpressionType.And); RunBinaryMockTests(ExpressionType.Or); RunBinaryMockTests(ExpressionType.ExclusiveOr); RunBinaryMockTests(ExpressionType.LeftShift); RunBinaryMockTests(ExpressionType.RightShift); RunBinaryMockTests(ExpressionType.AddAssign); RunBinaryMockTests(ExpressionType.SubtractAssign); RunBinaryMockTests(ExpressionType.DivideAssign); RunBinaryMockTests(ExpressionType.MultiplyAssign); RunBinaryMockTests(ExpressionType.ModuloAssign); RunBinaryMockTests(ExpressionType.AndAssign); RunBinaryMockTests(ExpressionType.OrAssign); RunBinaryMockTests(ExpressionType.ExclusiveOrAssign); RunBinaryMockTests(ExpressionType.LeftShiftAssign); RunBinaryMockTests(ExpressionType.RightShiftAssign); } [Test] public void TestInvokeSubtract() { Assert.AreEqual(Dynamic.InvokeBinaryOperator(1, ExpressionType.Subtract, 2), -1); } } } ================================================ FILE: Tests/Linq.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using NUnit.Framework; using IronPython.Hosting; using Microsoft.Scripting; namespace Dynamitey.Tests { [TestFixture] public class Linq : Helper { [Test] public void SimpleLinqDynamicLinq() { var expected = Enumerable.Range(1, 10).Where(i => i > 5).Skip(1).Take(2).Max(); var actual = Dynamic.Linq(Enumerable.Range(1, 10)).Where(new Func(i => i > 5)).Skip(1).Take(2).Max(); Assert.AreEqual(expected, actual); } [Test] public void MoreGenericsDynamicLinq() { var expected = Enumerable.Range(1, 10).Select(i => Tuple.Create(1, i)).Aggregate(0, (accum, each) => each.Item2); var actual = Dynamic.Linq(Enumerable.Range(1, 10)) .Select(new Func>(i => Tuple.Create(1, i))) .Aggregate(0, new Func, int>((accum, each) => each.Item2)); Assert.AreEqual(expected, actual); } private dynamic RunPythonHelper(object linq, string code) { var tEngine = Python.CreateEngine(); var tScope = tEngine.CreateScope(); tScope.SetVariable("linq", linq); var tSource = tEngine.CreateScriptSourceFromString(code.Trim(), SourceCodeKind.Statements); var tCompiled = tSource.Compile(); tCompiled.Execute(tScope); return tScope.GetVariable("result"); } [Test] public void PythonDynamicLinqGenericArgs() { var start = new Object[] { 1, "string", 4, Guid.Empty, 6 }; var expected = start.OfType().Skip(1).First(); var actual = RunPythonHelper(Dynamic.Linq(start), @" import System result = linq.OfType[System.Int32]().Skip(1).First() "); Assert.AreEqual(expected, actual); } [Test] public void PythonDynamicLinq() { var expected = Enumerable.Range(1, 10).Where(x => x < 5).OrderBy(x => 10 - x).First(); var actual = RunPythonHelper(Dynamic.Linq(Enumerable.Range(1, 10)), @" import System result = linq.Where.Overloads[System.Func[int, bool]](lambda x: x < 5).OrderBy(lambda x: 10-x).First() "); Assert.AreEqual(expected, actual); } [Test] public void PrintOutInterface() { var tList = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).OrderBy(it => it.Name). ToList(); Console.WriteLine("public interface ILinq:IEnumerable"); Console.WriteLine("{"); foreach (var line in tList .Where(it => it.GetParameters().Any() && (HelperIsGenericExtension(it, typeof(IEnumerable<>)) || it.GetParameters().First().ParameterType == typeof(IEnumerable)) ) .Select(HelperMakeName)) { Console.WriteLine("\t" + line); } Console.WriteLine("}"); Console.WriteLine(); Console.WriteLine("public interface IOrderedLinq : ILinq, IOrderedEnumerable"); Console.WriteLine("{"); foreach (var line in tList .Where(it => it.GetParameters().Any() && HelperIsGenericExtension(it, typeof(IOrderedEnumerable<>)) ) .Select(HelperMakeName)) { Console.WriteLine("\t" + line); } Console.WriteLine("}"); Console.WriteLine(); Console.WriteLine("//Skipped Methods"); foreach (var line in tList .Where(it => it.GetParameters().Any() && !(HelperIsGenericExtension(it, typeof(IEnumerable<>))) && !(HelperIsGenericExtension(it, typeof(IOrderedEnumerable<>))) && !(it.GetParameters().First().ParameterType == typeof(IEnumerable))) .Select(HelperMakeNameDebug)) { Console.WriteLine("//" + line); } } private bool HelperIsGenericExtension(MethodInfo it, Type genericType) { return it.GetParameters().First().ParameterType.IsGenericType && it.GetParameters().First().ParameterType.GetGenericTypeDefinition() == genericType && HelperSignleGenericArgMatch(it.GetParameters().First().ParameterType.GetGenericArguments().Single()); } bool HelperSignleGenericArgMatch(Type info) { foreach (var name in new[] { "TSource", "TFirst", "TOuter" }) { if (info.Name == name) { return true; } } return false; } // Define other methods and classes here string HelperFormatType(Type it) { if (HelperSignleGenericArgMatch(it)) { return "TSource"; } if (it.IsGenericType) { return String.Format("{0}<{1}>", it.Name.Substring(0, it.Name.IndexOf("`")), String.Join(",", it.GetGenericArguments().Select(a => HelperFormatType(a)))); } else { return it.Name; } } string HelperGenericParams(Type[] it) { var tArgs = it.Where(t => !HelperSignleGenericArgMatch(t)).Select(t => HelperFormatType(t)); if (!tArgs.Any()) { return ""; } return "<" + String.Join(",", tArgs) + ">"; } string HelperReturnTypeSub(Type it) { if (it.IsGenericType && (it.GetGenericTypeDefinition() == typeof(IEnumerable<>))) { return String.Format("ILinq<{0}>", HelperFormatType(it.GetGenericArguments().Single())); } if (it.IsGenericType && (it.GetGenericTypeDefinition() == typeof(IOrderedEnumerable<>))) { return String.Format("IOrderedLinq<{0}>", HelperFormatType(it.GetGenericArguments().Single())); } return HelperFormatType(it); } string HelperGetParams(ParameterInfo[] it) { var parms = it.Skip(1); return String.Join(",", parms.Select(p => HelperFormatType(p.ParameterType) + " " + p.Name)); } string HelperGetParamsDebug(ParameterInfo[] it) { var parms = it; return String.Join(",", parms.Select(p => HelperFormatType(p.ParameterType) + " " + p.Name)); } string HelperMakeName(MethodInfo it) { return String.Format("{0} {1}{2}({3});", HelperReturnTypeSub(it.ReturnType), it.Name, HelperGenericParams(it.GetGenericArguments()), HelperGetParams(it.GetParameters())); } string HelperMakeNameDebug(MethodInfo it) { return String.Format("{0} {1}{2}({3});", HelperReturnTypeSub(it.ReturnType), it.Name, HelperGenericParams(it.GetGenericArguments()), HelperGetParamsDebug(it.GetParameters())); } } } ================================================ FILE: Tests/MimicTest.cs ================================================ using System; using NUnit.Framework; namespace Dynamitey.Tests { /// /// This is the craziest set of tests I've ever written in my life... /// [TestFixture] public class MimicTest { private class SubMimic : DynamicObjects.Mimic { public int Add(int x, int y) { return x + y; } public string Add(string x, string y) { return x + y; } } [Test] public void Get_Property() { dynamic mimic = new DynamicObjects.Mimic(); dynamic result = mimic.I.Can.Get.Any.Property.I.Want.And.It.Wont.Blow.Up; Assert.That((object)result, Is.TypeOf()); } [Test] public void Set_Property() { dynamic mimic = new DynamicObjects.Mimic(); dynamic result = mimic.I.Can.Set.Any.Property.I.Want.And.It.Wont.Blow = "Up"; Assert.That((object)result, Is.EqualTo("Up")); } [Test] public void Call_Method() { dynamic mimic = new DynamicObjects.Mimic(); dynamic result = mimic.I.Can.Call.Any.Method.I.Want.And.It.Wont.Blow.Up(); Assert.That((object)result, Is.TypeOf()); } [Test] public void Call_Method_With_Parameters() { dynamic mimic = new DynamicObjects.Mimic(); dynamic result = mimic.I().Can().Call().Any().Method().I().Want().And().It().Wont().Blow().Up("And", "Any", "Parameter", "I", "Want", 1, 2, 3, 44.99m); Assert.That((object)result, Is.TypeOf()); } [Test] public void Get_Index() { dynamic mimic = new DynamicObjects.Mimic(); dynamic result = mimic["I"]["Can"]["Get"]["Indexes"]["All"]["Day"]["Like"]["It"]["Aint"]["No"]["Thang"]; Assert.That((object)result, Is.TypeOf()); } [Test] public void Set_Index() { dynamic mimic = new DynamicObjects.Mimic(); dynamic result = mimic["I"]["Can"]["Set"]["Indexes"]["All"]["Day"]["Like"]["It"]["Aint"]["No"] = "Thang"; Assert.That((object)result, Is.EqualTo("Thang")); } [Test] public void Cast() { dynamic mimic = new DynamicObjects.Mimic(); int Int32 = mimic; Assert.That(Int32,Is.EqualTo(0)); double Double = mimic; Assert.That(Double, Is.EqualTo(0.0d)); float Float = mimic; Assert.That(Float, Is.EqualTo(0.0f)); object Object = mimic; Assert.That(Object, Is.TypeOf()); Guid Guid = mimic; Assert.That(Guid, Is.EqualTo(Guid.Empty)); DateTime DateTime = mimic; Assert.That(DateTime, Is.EqualTo(default(DateTime))); } [Test] public void Unary() { dynamic mimic = new DynamicObjects.Mimic(); dynamic result; result = !mimic; Assert.That((object)result, Is.TypeOf()); result = ++mimic; Assert.That((object)result, Is.TypeOf()); result = --mimic; Assert.That((object)result, Is.TypeOf()); result = mimic++; Assert.That((object)result, Is.TypeOf()); result = mimic--; Assert.That((object)result, Is.TypeOf()); result = mimic += 1; Assert.That((object)result, Is.TypeOf()); result = mimic -= 1; Assert.That((object)result, Is.TypeOf()); result = mimic /= 2; Assert.That((object)result, Is.TypeOf()); result = mimic *= 4; Assert.That((object)result, Is.TypeOf()); result = mimic ^= true; Assert.That((object)result, Is.TypeOf()); result = mimic |= true; Assert.That((object)result, Is.TypeOf()); result = mimic &= false; Assert.That((object)result, Is.TypeOf()); result = mimic %= 5; Assert.That((object)result, Is.TypeOf()); } [Test] public void Binary() { dynamic thing1 = new DynamicObjects.Mimic(); dynamic thing2 = new DynamicObjects.Mimic(); dynamic result; result = thing1 + thing2; Assert.That((object)result, Is.TypeOf()); result = thing1 - thing2; Assert.That((object)result, Is.TypeOf()); result = thing1 / thing2; Assert.That((object)result, Is.TypeOf()); result = thing1 * thing2; Assert.That((object)result, Is.TypeOf()); result = thing1 | thing2; Assert.That((object)result, Is.TypeOf()); result = thing1 & thing2; Assert.That((object)result, Is.TypeOf()); result = thing1 ^ thing2; Assert.That((object)result, Is.TypeOf()); result = thing1 % thing2; Assert.That((object)result, Is.TypeOf()); } [Test] public void Inheritance_Int() { dynamic mimic = new SubMimic(); int result = mimic.Add(2, 2); Assert.AreEqual(4, result); } [Test] public void Inheritance_String() { dynamic mimic = new SubMimic(); string result = mimic.Add("He", "llo"); Assert.AreEqual("Hello", result); } [Test] public void Inheritance_No_Match() { dynamic mimic = new SubMimic(); int result = mimic.Add(1, "llo"); Assert.AreEqual(default(int), result); } } } ================================================ FILE: Tests/PrivateTest.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Dynamitey.SupportLibrary; using Microsoft.CSharp.RuntimeBinder; using NUnit.Framework; namespace Dynamitey.Tests { [TestFixture] public class PrivateTest : Helper { [Test] public void TestInvokePrivateMethod() { var tTest = new TestWithPrivateMethod(); Assert.That((object)Dynamic.InvokeMember(tTest, "Test"), Is.EqualTo(3)); } [Test] public void TestInvokePrivateMethodAcrossAssemblyBoundries() { var tTest = new PublicType(); Assert.That((object)Dynamic.InvokeMember(tTest, "PrivateMethod", 3), Is.True); } [Test] public void TestInvokeInternalTypeMethodAcrossAssemblyBoundries() { var tTest = PublicType.InternalInstance; Assert.That((object)Dynamic.InvokeMember(tTest, "InternalMethod", 3), Is.True); } [Test] public void TestInvokeDoNotExposePrivateMethod() { var tTest = new TestWithPrivateMethod(); var context = InvokeContext.CreateContext; Assert.That(() => Dynamic.InvokeMember(context(tTest,this), "Test"), Throws.InstanceOf()); } [Test] public void TestCacheableDoNotExposePrivateMethod() { var tTest = new TestWithPrivateMethod(); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Test"); Assert.That(() => tCachedInvoke.Invoke(tTest), Throws.InstanceOf()); } [Test] public void TestCacheableExposePrivateMethodViaInstance() { var tTest = new TestWithPrivateMethod(); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Test", context: tTest); Assert.That(tCachedInvoke.Invoke(tTest), Is.EqualTo(3)); } [Test] public void TestCacheableExposePrivateMethodViaType() { var tTest = new TestWithPrivateMethod(); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Test", context: typeof(TestWithPrivateMethod)); Assert.That( tCachedInvoke.Invoke(tTest), Is.EqualTo(3)); } } public class TestWithPrivateMethod { private int Test() { return 3; } } } ================================================ FILE: Tests/SpeedTest.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Dynamitey.SupportLibrary; using NUnit.Framework; using Microsoft.FSharp.Reflection; namespace Dynamitey.Tests { [TestFixture] [Category("Performance")] public class SpeedTest:Helper { [OneTimeSetUp] public void WarmUpDlr() { Dynamic.InvokeMember(1, "ToString"); } public TimeIt Timer; [SetUp] public void Setup() { Timer = new TimeIt(); } [Test] public void PropPocoGetValueTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tSetValue = "1"; var tAnon = new { TestGet = tSetValue }; Timer.Action1 = () => { var tOut = Dynamic.InvokeGet(tAnon, "TestGet"); }; var tPropertyInfo = tAnon.GetType().GetProperty("TestGet"); Timer.Action2 = () => { var tOut = tPropertyInfo.GetValue(tAnon, null); }; var elapsed = Timer.Go(5 * TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableGetValueTimed() { var tSetValue = "1"; var tAnon = new PropPoco() { Prop1 = tSetValue }; var tInvoke = new CacheableInvocation(InvocationKind.Get, "Prop1"); Timer.Action1 = () => { var tOut = tInvoke.Invoke(tAnon); }; var tPropertyInfo = tAnon.GetType().GetProperty("Prop1"); Timer.Action2 = () => { var tOut = tPropertyInfo.GetValue(tAnon, null); }; var elapsed = Timer.Go(2*TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void ConstructorTimed() { Timer.Action1 = (() => { var tOut = Dynamic.InvokeConstructor(typeof(Tuple), "Test"); }); Timer.Action2 = (() => { var tOut = Activator.CreateInstance(typeof(Tuple), "Test"); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableConstructorTimed() { var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor, argCount: 1); Timer.Action1 = (() => { var tOut = tCachedInvoke.Invoke(typeof(Tuple), "Test"); }); Timer.Action2 = (() => { var tOut = Activator.CreateInstance(typeof(Tuple), "Test"); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void ConstructorNoARgTimed() { Timer.Action1=(() => { var tOut = Dynamic.InvokeConstructor(typeof(List)); }); Timer.Action2=(() => { var tOut = Activator.CreateInstance(typeof(List)); }); Timer.Action3=(() => { var tOut = Activator.CreateInstance>(); }); var elapsed = Timer.GoThree(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Refelection Generic: " + elapsed.Item3); Console.WriteLine("Impromptu VS Reflection: {0:0.0} x slower", (double)elapsed.Item1.Ticks / elapsed.Item2.Ticks); Assert.Ignore("I don't think this is beatable at the moment"); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CachableConstructorNoARgTimed() { var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(typeof(List)); }); Timer.Action2=(() => { var tOut = Activator.CreateInstance(typeof(List)); }); Timer.Action3=(() => { var tOut = Activator.CreateInstance>(); }); var elapsed = Timer.GoThree(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Refelection Generic: " + elapsed.Item3); Console.WriteLine("Impromptu VS Reflection: {0:0.0} x slower", (double)elapsed.Item1.Ticks / elapsed.Item2.Ticks); Assert.Ignore("I don't think this is beatable at the moment"); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void ConstructorValueTypeTimed() { Timer.Action1=(() => { var tOut = Dynamic.InvokeConstructor(typeof(DateTime), 2010, 1, 20); }); Timer.Action2=(() => { var tOut = Activator.CreateInstance(typeof(DateTime), 2010, 1, 20); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CachedConstructorValueTypeTimed() { var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor, argCount: 3); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(typeof(DateTime), 2010, 1, 20); }); Timer.Action2=(() => { var tOut = Activator.CreateInstance(typeof(DateTime), 2010, 1, 20); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void MethodPocoGetValueTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tValue = 1; Timer.Action1=(() => { var tOut = Dynamic.InvokeMember(tValue, "ToString"); }); var tMethodInfo = tValue.GetType().GetMethod("ToString", new Type[] { }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { }); }); var elapsed = Timer.Go(2* TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableMethodPocoGetValueTimed() { var tValue = 1; var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "ToString"); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(tValue); }); var tMethodInfo = tValue.GetType().GetMethod("ToString", new Type[] { }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { }); }); var elapsed = Timer.Go(3* TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void GetStaticTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tStaticType = typeof(DateTime); var tTarget = InvokeContext.CreateStatic(tStaticType); Timer.Action1=(() => { var tOut = Dynamic.InvokeGet(tTarget, "Today"); }); var tMethodInfo = typeof(DateTime).GetProperty("Today").GetGetMethod(); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tStaticType, new object[] { }); }); var elapsed = Timer.Go(3 * TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableGetStaticTimed() { var tStaticType = typeof(DateTime); var tContext = InvokeContext.CreateStatic(tStaticType); var tCachedInvoke = new CacheableInvocation(InvocationKind.Get, "Today", context: tContext); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(tStaticType); }); var tMethodInfo = typeof(DateTime).GetProperty("Today").GetGetMethod(); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tStaticType, new object[] { }); }); var elapsed = Timer.Go(3 * TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void MethodStaticMethodValueTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tStaticType = typeof(DateTime); var tTarget = InvokeContext.CreateStatic(tStaticType); string tDate = "01/20/2009"; Timer.Action1=(() => { var tOut = Dynamic.InvokeMember(tTarget, "Parse", tDate); }); var tMethodInfo = typeof(DateTime).GetMethod("Parse", new[] { typeof(string) }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tStaticType, new object[] { tDate }); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableMethodStaticMethodValueTimed() { var tStaticType = typeof(DateTime); var tContext = InvokeContext.CreateStatic(tStaticType); string tDate = "01/20/2009"; var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Parse", argCount: 1, context: tContext); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(tStaticType, tDate); }); var tMethodInfo = typeof(DateTime).GetMethod("Parse", new[] { typeof(string) }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tStaticType, new object[] { tDate }); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void MethodPocoGetValuePassNullTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tValue = new OverloadingMethPoco(); Timer.Action1=(() => { var tOut = Dynamic.InvokeMember(tValue, "Func", null); }); var tMethodInfo = tValue.GetType().GetMethod("Func", new Type[] { typeof(object)}); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { null}); }); var elapsed = Timer.Go(3 * TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableMethodPocoGetValuePassNullTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tValue = new OverloadingMethPoco(); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Func", argCount:1); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(tValue, null); }); var tMethodInfo = tValue.GetType().GetMethod("Func", new Type[] { typeof(object) }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { null }); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void MethodPocoGetValuePassNullDoubleCallTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tValue = new OverloadingMethPoco(); Timer.Action1=(() => { var tOut = Dynamic.InvokeMember(tValue, "Func", null); var tOut2 = Dynamic.InvokeMember(tValue, "Func", 2); }); var tMethodInfo = tValue.GetType().GetMethod("Func", new Type[] { typeof(object) }); var tMethodInfo2 = tValue.GetType().GetMethod("Func", new Type[] { typeof(int) }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { null }); var tOut2 = tMethodInfo2.Invoke(tValue, new object[] { 2 }); }); var elapsed = Timer.Go(3 * TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableMethodPocoGetValuePassNullDoubleCallTimed() { var tValue = new OverloadingMethPoco(); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "Func", 1); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(tValue, null); var tOut2 = tCachedInvoke.Invoke(tValue, 2); }); var tMethodInfo = tValue.GetType().GetMethod("Func", new Type[] { typeof(object) }); var tMethodInfo2 = tValue.GetType().GetMethod("Func", new Type[] { typeof(int) }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { null }); var tOut2 = tMethodInfo2.Invoke(tValue, new object[] { 2 }); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void MethodPocoGetValue4argsTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tValue = "test 123 45 string"; Timer.Action1=(() => { var tOut = Dynamic.InvokeMember(tValue, "IndexOf", "45", 0, 14, StringComparison.InvariantCulture); }); var tMethodInfo = tValue.GetType().GetMethod("IndexOf", new Type[] { typeof(string), typeof(int), typeof(int), typeof(StringComparison) }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { "45", 0, 14, StringComparison.InvariantCulture }); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableMethodPocoGetValue4argsTimed() { var tValue = "test 123 45 string"; var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember, "IndexOf", 4); Timer.Action1=(() => { var tOut = tCachedInvoke.Invoke(tValue,"45", 0, 14, StringComparison.InvariantCulture); }); var tMethodInfo = tValue.GetType().GetMethod("IndexOf", new Type[] { typeof(string), typeof(int), typeof(int), typeof(StringComparison) }); Timer.Action2=(() => { var tOut = tMethodInfo.Invoke(tValue, new object[] { "45", 0, 14, StringComparison.InvariantCulture }); }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void MethodPocoVoidTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tValue = new Dictionary(); Timer.Action1=(() => Dynamic.InvokeMemberAction(tValue, "Clear")); var tMethodInfo = tValue.GetType().GetMethod("Clear", new Type[] { }); Timer.Action2=(() => tMethodInfo.Invoke(tValue, new object[] { })); var elapsed = Timer.Go(5 * TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableMethodPocoVoidTimed() { var tValue = new Dictionary(); var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMemberAction, "Clear"); Timer.Action1=(() => tCachedInvoke.Invoke(tValue)); var tMethodInfo = tValue.GetType().GetMethod("Clear", new Type[] { }); Timer.Action2=(() => tMethodInfo.Invoke(tValue, new object[] { })); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void SetTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tPoco1 = new PropPoco(); var tPoco2 = new PropPoco(); var tSetValue = "1"; Timer.Action1 = () => Dynamic.InvokeSet(tPoco1, "Prop1", tSetValue); var tPropertyInfo = tPoco2.GetType().GetProperty("Prop1"); Timer.Action2 = () => tPropertyInfo.SetValue(tPoco2, tSetValue, new object[] { }); var elapsed = Timer.Go(5* TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableSetTimed() { var tPoco1 = new PropPoco(); var tPoco2 = new PropPoco(); var tSetValue = "1"; var tCacheable = new CacheableInvocation(InvocationKind.Set, "Prop1"); Timer.Action1 = () => tCacheable.Invoke(tPoco1, tSetValue); var tPropertyInfo = tPoco2.GetType().GetProperty("Prop1"); Timer.Action2 = () => tPropertyInfo.SetValue(tPoco2, tSetValue, new object[] { }); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void CacheableSetNullTimed() { var tPoco = new PropPoco(); String tSetValue = null; var tCachedInvoke = new CacheableInvocation(InvocationKind.Set, "Prop1"); Timer.Action1 = (() => tCachedInvoke.Invoke(tPoco, tSetValue)); var tPropertyInfo = tPoco.GetType().GetProperty("Prop1"); Timer.Action2 = (() => tPropertyInfo.SetValue(tPoco, tSetValue, new object[] { })); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void SetNullTimed() { #if DEBUG Assert.Ignore("Visual Studio slows down dynamic too much in debug mode"); #endif var tPoco1 = new PropPoco(); var tPoco2 = new PropPoco(); String tSetValue = null; Timer.Action1 = () => Dynamic.InvokeSet(tPoco1, "Prop1", tSetValue); var tPropertyInfo = tPoco2.GetType().GetProperty("Prop1"); Timer.Action2 = () => tPropertyInfo.SetValue(tPoco2, tSetValue, new object[] { }); var elapsed = Timer.Go(5 * TimeIt.Million); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void FastDynamicInvoke() { Func tFunc = it => it > 10; Timer.Action1 =(() => tFunc.FastDynamicInvoke(5)); Timer.Action2 = (() => tFunc.DynamicInvoke(5)); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void FastDynamicInvokeAction() { Action tFunc = it => it.ToString(); Timer.Action1 = (() => tFunc.FastDynamicInvoke(5)); Timer.Action2 = (() => tFunc.DynamicInvoke(5)); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void IsTupleTimed() { object tup = Tupler.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); Timer.Action1 = () => Tupler.IsTuple(tup); Timer.Action2 = () => FSharpType.IsTuple(tup.GetType()); var elapsed = Timer.Go(); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("FSharp Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS FSharp Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void TupleIndexTimed() { object tup = Tupler.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); Timer.Action1 = () => Tupler.Index(tup,14); Timer.Action2 = () => FSharpValue.GetTupleField(tup,14); var elapsed = Timer.Go(50000); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("FSharp Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS FSharp Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void TupleToListTimed() { object tup = Tupler.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); Timer.Action1 = () => Tupler.ToList(tup); Timer.Action2 = () => FSharpValue.GetTupleFields(tup).ToList(); var elapsed = Timer.Go(50000); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("FSharp Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS FSharp Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } [Test] public void ListToTupleTimed() { var list = new object[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; Timer.Action1 = () => Tupler.ToTuple(list); Timer.Action2 = () => { var types = list.Select(it => it.GetType()).ToArray(); var tupType = FSharpType.MakeTupleType(types); FSharpValue.MakeTuple(list, tupType); }; var elapsed = Timer.Go(50000); Console.WriteLine("Impromptu: " + elapsed.Item1); Console.WriteLine("FSharp Refelection: " + elapsed.Item2); Console.WriteLine("Impromptu VS FSharp Reflection: {0}", TimeIt.RelativeSpeed(elapsed)); Assert.Less(elapsed.Item1, elapsed.Item2); } } } ================================================ FILE: Tests/Tests.csproj ================================================  net8.0;net48 false ================================================ FILE: Tests/TimeIt.cs ================================================ using System; using System.Diagnostics; using NUnit.Framework; namespace Dynamitey.Tests { public class TimeIt { public const int Million = 1000000; private Stopwatch _watch1; private Stopwatch _watch2; private Stopwatch _watch3; private bool _skipInitializationCosts; public TimeIt(bool skipInitializationCosts = false) { _watch1 = new Stopwatch(); _watch2 = new Stopwatch(); _watch3 = new Stopwatch(); _skipInitializationCosts = skipInitializationCosts; } public Tuple GoThree(int iteration = Million, bool useThree = true) { if (_skipInitializationCosts) { iteration++; } for (int i = 0; i < iteration; i++) { _watch1.Start(); Action1(); _watch1.Stop(); _watch2.Start(); Action2(); _watch2.Stop(); if (useThree) { _watch3.Start(); Action3(); _watch3.Stop(); } if (i == 0 && _skipInitializationCosts) { _watch1.Reset(); _watch2.Reset(); _watch3.Reset(); } } return Tuple.Create(_watch1.Elapsed, _watch2.Elapsed, _watch3.Elapsed); } public Tuple Go(int iteration = Million) { var goThree = GoThree(iteration, false); return Tuple.Create(goThree.Item1, goThree.Item2); } public Action Action1 { get; set; } public Action Action2 { get; set; } public Action Action3 { get; set; } public static string RelativeSpeed(Tuple elapsed) { if ( (elapsed.Item2 > elapsed.Item1 && (double)elapsed.Item2.Ticks / elapsed.Item1.Ticks < 1.4) || (elapsed.Item1 > elapsed.Item2 && (double)elapsed.Item1.Ticks / elapsed.Item2.Ticks < 1.4) ) { Assert.Ignore("Equivalent"); } if (elapsed.Item2 > elapsed.Item1) return String.Format(" {0:0.0} x faster", (double)elapsed.Item2.Ticks / elapsed.Item1.Ticks); if (elapsed.Item1 > elapsed.Item2) return String.Format(" {0:0.0} x slower", (double)elapsed.Item1.Ticks / elapsed.Item2.Ticks); return String.Format("Equivalent"); } } } ================================================ FILE: Tests/TuplerTest.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Dynamitey; using NUnit.Framework; namespace Dynamitey.Tests { [TestFixture] public class TuplerTest { [Test] public void DynamicCreateTypedTuple() { object tup = Tupler.Create(1, "2", "3", 4); var tup2 = Tuple.Create(1, "2", "3", 4); Assert.That(tup, Is.TypeOf(tup2.GetType())); Assert.That(tup, Is.EqualTo(tup2)); } [Test] public void DynamicCreateTypedTuple8() { object tup = Tupler.Create(1, "2", "3", 4, 5, 6, 7, "8"); var tup2 = Tuple.Create(1, "2", "3", 4, 5, 6, 7, "8"); Assert.That(tup,Is.TypeOf(tup2.GetType())); Assert.That(tup, Is.EqualTo(tup2)); } [Test] public void DynamicCreateLongTypedTuple() { object tup = Tupler.Create(1, "2", "3", 4, 5, 6, 7, "8", "9", 10, "11", 12); var tup2 = new Tuple>( 1, "2", "3", 4, 5, 6, 7, Tuple.Create("8", "9", 10, "11", 12) ); Assert.That(tup, Is.TypeOf(tup2.GetType())); Assert.That(tup, Is.EqualTo(tup2)); } [Test] public void DynamicTupleSize() { var tup = Tuple.Create(1, 2, 3, 4, 5); Assert.That((object)Tupler.Size(tup),Is.EqualTo(5)); } [Test] public void DynamicTupleSize8() { var tup = Tuple.Create(1, 2, 3, 4, 5,6,7,8); Assert.That((object)Tupler.Size(tup), Is.EqualTo(8)); } [Test] public void DynamicTupleSize20() { var tup = Tupler.Create(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); Assert.That((object)Tupler.Size(tup), Is.EqualTo(20)); } [Test] public void DynamicTupleToList() { var tup =Tuple.Create(1, 2, 3, 4, 5); var exp=Enumerable.Range(1,5).ToList(); Assert.That((object)Tupler.ToList(tup),Is.EqualTo(exp)); } [Test] public void DynamicTupleToList8() { var tup = Tuple.Create(1, 2, 3, 4, 5, 6, 7, 8); var exp = Enumerable.Range(1, 8).ToList(); Assert.That((object)Tupler.ToList(tup), Is.EqualTo(exp)); } [Test] public void DynamicTupleToList20() { var tup = Tupler.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); var exp = Enumerable.Range(1, 20).ToList(); Assert.That((object)Tupler.ToList(tup), Is.EqualTo(exp)); } [Test] public void DynamicListToTuple() { var exp = Enumerable.Range(1, 5).ToList(); var tup = exp.ToTuple(); Assert.That((object)Tupler.IsTuple(tup), Is.True); Assert.That((object)Tupler.ToList(tup), Is.EqualTo(exp)); } [Test] public void DynamicListToTuplet8() { var exp = Enumerable.Range(1, 8).ToList(); var tup = exp.ToTuple(); Assert.That((object)Tupler.IsTuple(tup), Is.True); Assert.That((object)Tupler.ToList(tup), Is.EqualTo(exp)); } [Test] public void DynamicListToTuple20() { var exp = Enumerable.Range(1, 20).ToList(); var tup = exp.ToTuple(); Assert.That((object)Tupler.IsTuple(tup), Is.True); Assert.That((object)Tupler.ToList(tup), Is.EqualTo(exp)); } [Test] public void DynamicTupleIndex() { var tup = Tupler.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); Assert.That((object)Tupler.Index(tup,5), Is.EqualTo(6)); } [Test] public void DynamicTupleIndex7() { var tup = Tupler.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); Assert.That((object)Tupler.Index(tup, 7), Is.EqualTo(8)); } [Test] public void DynamicTupleIndex19() { var tup = Tupler.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); Assert.That((object)Tupler.Index(tup, 19), Is.EqualTo(20)); } } } ================================================ FILE: Version.props ================================================ 3.0.4 preview$(GITHUB_RUN_NUMBER) ================================================ FILE: build.fsx ================================================ #!/bin/sh #if bin_sh # Doing this because arguments can't be used with /usr/bin/env on linux, just mac exec fsharpi --define:mono_posix --exec $0 $* #endif #if FSharp_MakeFile (* * Single File Crossplatform FSharp Makefile Bootstrapper * Apache licensed - Copyright 2014 Jay Tuley * v 2.0 https://gist.github.com/jbtule/11181987 * * How to use: * On Windows `fsi --exec build.fsx * *Note:* if you have trouble first run "%vs120comntools%\vsvars32.bat" or use the "Developer Command Prompt for VS201X" * or install https://github.com/Iristyle/Posh-VsVars#posh-vsvars * * On Mac Or Linux `./build.fsx ` * *Note:* But if you have trouble then use `sh build.fsx ` * *) #I "packages/FAKE/tools" #r "FakeLib.dll" #r "System.Xml.Linq.dll" open Fake open System.Xml.Linq open System.Xml.XPath let sln = "./Dynamitey.sln" let commonBuild target = let buildMode = getBuildParamOrDefault "configuration" "Release" let vsuffix = getBuildParamOrDefault "vsuffix" "" let versionPrefix = "Version.props" |> System.IO.File.ReadAllText |> XDocument.Parse |> (fun x -> x.XPathEvaluate("//VersionPrefix/text()")) |> (fun x-> x :?> seq) |> Seq.exactlyOne |> sprintf "%A" let vProp = if System.Text.RegularExpressions.Regex.IsMatch(vsuffix, "^\d+$") then "Version", versionPrefix + "." + vsuffix else "VersionSuffix", vsuffix let setParams defaults = { defaults with Verbosity = Some(Quiet) Targets = [target] Properties = [ "Configuration", buildMode vProp ] } build setParams sln |> DoNothing Target "Restore" (fun () -> trace " --- Restore Packages --- " //because nuget doesn't know how to find msbuild15 on linux let restoreProj = fun args -> directExec (fun info -> info.FileName <- "msbuild" info.Arguments <- "/t:restore " + args) |> ignore sln |> restoreProj ) Target "Clean" (fun () -> trace " --- Cleaning stuff --- " commonBuild "Clean" ) Target "Build" (fun () -> trace " --- Building the libs --- " commonBuild "Build" ) Target "Test" (fun () -> trace " --- Test the libs --- " let nunit3exe = "./packages/nunit.consolerunner/3.7.0/tools/nunit3-console.exe" let buildMode = getBuildParamOrDefault "configuration" "Release" let testDir = sprintf "./Tests/bin/%s/net462/" buildMode let netExe, netAppVeyor,coreAppVeyor = if buildServer = AppVeyor then "nunit3-console","--result=myresults.xml;format=AppVeyor", "--logger=trx;LogFileName=testresults.trx" else nunit3exe,"--noresult","" let s1 = directExec (fun info -> info.FileName <- netExe info.Arguments <- sprintf "--labels=All %s --where=\"cat != Performance\" %s" netAppVeyor (testDir + "Tests.exe")) let s2 = directExec (fun info -> info.FileName <- "dotnet" info.Arguments <- sprintf "test Tests/Tests.csproj -f netcoreapp2.0 --no-build --no-restore --filter=TestCategory!=Performance %s --configuration=%s" coreAppVeyor buildMode) let appveyor = environVarOrNone "APPVEYOR_JOB_ID" match appveyor with | Some(jobid) -> use webClient = new System.Net.WebClient() webClient.UploadFile(sprintf "https://ci.appveyor.com/api/testresults/mstest/%s" jobid,"./Tests/TestResults/testresults.trx") |> ignore | None -> () if(not s1 || not s2) then failwith "Tests failed" ) "Restore" ==> "Build" ==> "Test" RunTargetOrDefault "Test" #else open System open System.IO open System.Diagnostics (* helper functions *) #if mono_posix #r "Mono.Posix.dll" open Mono.Unix.Native let applyExecutionPermissionUnix path = let _,stat = Syscall.lstat(path) Syscall.chmod(path, FilePermissions.S_IXUSR ||| stat.st_mode) |> ignore #else let applyExecutionPermissionUnix path = () #endif let doesNotExist path = path |> Path.GetFullPath |> File.Exists |> not let execAt (workingDir:string) (exePath:string) (args:string seq) = let processStart (psi:ProcessStartInfo) = let ps = Process.Start(psi) ps.WaitForExit () ps.ExitCode let fullExePath = exePath |> Path.GetFullPath applyExecutionPermissionUnix fullExePath let exitCode = ProcessStartInfo( fullExePath, args |> String.concat " ", WorkingDirectory = (workingDir |> Path.GetFullPath), UseShellExecute = false) |> processStart if exitCode <> 0 then exit exitCode () let exec = execAt Environment.CurrentDirectory let downloadNugetTo path = let fullPath = path |> Path.GetFullPath; if doesNotExist fullPath then printf "Downloading NuGet..." use webClient = new System.Net.WebClient() fullPath |> Path.GetDirectoryName |> Directory.CreateDirectory |> ignore webClient.DownloadFile("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", path |> Path.GetFullPath) printfn "Done." let passedArgs = fsi.CommandLineArgs.[1..] |> Array.toList (* execution script customize below *) let makeFsx = fsi.CommandLineArgs.[0] let nugetExe = ".nuget/NuGet.exe" let fakeExe = "packages/FAKE/tools/FAKE.exe" downloadNugetTo nugetExe if doesNotExist fakeExe then exec nugetExe ["install"; "fake"; "-OutputDirectory packages"; "-ExcludeVersion"] exec fakeExe ([makeFsx; "-d:FSharp_MakeFile"] @ passedArgs) #endif