From 16a9ff433c7c714552c6e637ef013e3738996c97 Mon Sep 17 00:00:00 2001 From: Tom Atwood Date: Tue, 6 Aug 2024 18:19:42 -0400 Subject: [PATCH 1/2] Updated .NET tests to new NUnit 'Assert.That' --- Dynamitey/Dynamic.cs | 10 +- Tests/Curry.cs | 574 +++++---- Tests/DynamicObjects.cs | 1128 ++++++++--------- Tests/ExpandoObjs.cs | 105 +- Tests/Impromptu.cs | 16 +- Tests/Invoke.cs | 2541 +++++++++++++++++---------------------- Tests/Linq.cs | 16 +- Tests/MimicTest.cs | 6 +- 8 files changed, 1961 insertions(+), 2435 deletions(-) diff --git a/Dynamitey/Dynamic.cs b/Dynamitey/Dynamic.cs index 7517845..23550c0 100644 --- a/Dynamitey/Dynamic.cs +++ b/Dynamitey/Dynamic.cs @@ -134,7 +134,7 @@ public static CallSite CreateCallSite(Type delegateType, CallSiteBinder binder, /// }); /// var tSite = Impromptu.CreateCallSite(tBinder); /// tSite.Target.Invoke(tSite, tPoco, out tResult); - /// Assert.AreEqual("success", tResult); + /// Assert.That("success", Is.EqualTo(tResult)); /// ]]> /// /// @@ -189,7 +189,7 @@ public static dynamic Linq(object enumerable) /// var tValue = 1; /// var tOut = Impromptu.InvokeMember(tExpando, "Func", tValue); /// - /// Assert.AreEqual(tValue.ToString(), tOut); + /// Assert.That(tValue.ToString(), Is.EqualTo(tOut)); /// ]]> /// /// @@ -399,7 +399,7 @@ public static object InvokeSetIndex(object target, params object[] indexesThenVa /// /// Impromptu.InvokeMemberAction(tExpando, "Action", tValue); /// - /// Assert.AreEqual(tValue, tTest); + /// Assert.That(tValue, Is.EqualTo(tTest)); /// ]]> /// /// @@ -444,7 +444,7 @@ public static void InvokeAction(object target, params object[] args) /// /// Impromptu.InvokeSet(tExpando, "Test", tSetValue); /// - /// Assert.AreEqual(tSetValue, tExpando.Test); + /// Assert.That(tSetValue, Is.EqualTo(tExpando.Test)); /// ]]> /// /// @@ -561,7 +561,7 @@ public static dynamic Curry(Delegate target) /// /// var tOut =Impromptu.InvokeGet(tAnon, "Test"); /// - /// Assert.AreEqual(tSetValue, tOut); + /// Assert.That(tSetValue, Is.EqualTo(tOut)); /// ]]> /// /// diff --git a/Tests/Curry.cs b/Tests/Curry.cs index 7d34358..a8a9588 100644 --- a/Tests/Curry.cs +++ b/Tests/Curry.cs @@ -1,301 +1,283 @@ -using System.Text; +using System; +using System.Linq; +using System.Text; using Dynamitey.SupportLibrary; +using NUnit.Framework; namespace Dynamitey.Tests { - [TestFixture] - public class Curry - { - [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")); - } - } + [TestFixture] + public class Curry + { + [Test] + public void TestBasicDelegateCurry() + { + Func tAdd = (x, y) => x + y; + var tCurriedAdd4 = Dynamic.Curry(tAdd)(4); + var tResult = tCurriedAdd4(6); + + Assert.That(tResult, Is.EqualTo(10)); + } + + [Test] + public void TestBasicNamedCurry() + { + Func tSub = (x, y) => x - y; + var tCurriedSub7 = Dynamic.Curry(tSub)(arg2: 7); + var tResult = tCurriedSub7(arg1: 10); + + Assert.That(tResult, Is.EqualTo(3)); + } + + [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.That(tResult2, Is.EqualTo("410")); + } + + [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.That(tResult2, Is.EqualTo(14)); + } + + 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.That(tResult, Is.EqualTo(true)); + } + + 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.That(tBool, Is.EqualTo(true)); + } + + [Test] + public void TestBasicConvertDelegateCurryParamValueType() + { + Func tAdd = (x, y) => x + y; + var tCurriedAdd4 = Dynamic.Curry(tAdd)(4); + Func tCastToFunc = tCurriedAdd4; + var tResult2 = tCastToFunc(10); + + Assert.That(tResult2, Is.EqualTo(14)); + } + + [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.That(tResult, Is.EqualTo(20)); + } + + [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.That(tResult, Is.EqualTo(35)); + } + + [Test] + public void TestPococMethodCurry() + { + var tNewObj = new PocoAdder(); + + var tCurry = Dynamic.Curry(tNewObj).Add(4); + var tResult = tCurry(10); + Assert.That(tResult, Is.EqualTo(14)); + // Test cached invocation; + var tResult2 = tCurry(30); + Assert.That(tResult2, Is.EqualTo(34)); + } + + [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.That(result, Is.EqualTo("Test A, B, C, D")); + } + + [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.That(tResult, Is.EqualTo(14)); + // Test cached invocation; + var tResult2 = tCurry(30); + Assert.That(tResult2, Is.EqualTo(34)); + } + + [Test] + public void UnboundedCurry() + { + var tNewObject = Dynamic.Curry(Build.NewObject); + var tCurriedNewObject = tNewObject(One: 1); + var tResult = tCurriedNewObject(Two: 2); + Assert.That(tResult.One, Is.EqualTo(1)); + Assert.That(tResult.Two, Is.EqualTo(2)); + } + + [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.That(tResult.One, Is.EqualTo(1)); + Assert.That(tResult.Two, Is.EqualTo(2)); + Assert.That(tResult.Three, Is.EqualTo(3)); + } + + [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.That(tResult.One, Is.EqualTo(1)); + Assert.That(tResult.Two, Is.EqualTo(2)); + Assert.That(tResult.Three, Is.EqualTo(3)); + } + + [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.That(tResult, Is.EqualTo(10)); + } + + [Test] + public void UnboundedPartialApply() + { + var tNewObject = Dynamic.Curry(Build.NewObject); + tNewObject = tNewObject(One: 1, Two: 2); + var tResult = tNewObject(Three: 3, Four: 4); + Assert.That(tResult.One, Is.EqualTo(1)); + Assert.That(tResult.Two, Is.EqualTo(2)); + Assert.That(tResult.Three, Is.EqualTo(3)); + Assert.That(tResult.Four, Is.EqualTo(4)); + } + + [Test] + public void BasicCurryTest() + { + Func adder = (x, y, z) => x + y + z; + + var curried = Dynamic.Curry(adder); + + Assert.That(curried(1, 2, 3), Is.EqualTo(6)); + Assert.That(curried(1, 2)(3), Is.EqualTo(6)); + Assert.That(curried(1)(2, 3), Is.EqualTo(6)); + Assert.That(curried(1)(2)(3), Is.EqualTo(6)); + } + + [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")); + } + } } diff --git a/Tests/DynamicObjects.cs b/Tests/DynamicObjects.cs index f5c99a2..755aec7 100644 --- a/Tests/DynamicObjects.cs +++ b/Tests/DynamicObjects.cs @@ -1,574 +1,510 @@ -using System.Collections; +using System; +using System.Collections; +using System.Collections.Generic; using System.Dynamic; +using System.Linq; using System.Runtime.CompilerServices; +using NUnit.Framework; +using Dynamitey; +using Dynamitey.DynamicObjects; using Dynamitey.SupportLibrary; namespace Dynamitey.Tests { - [TestFixture] - public class DynamicObjs - { - - - - - [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); - } - + [TestFixture] + public class DynamicObjs + { + [Test] + public void GetterAnonTest() + { + var tAnon = new { Prop1 = "Test", Prop2 = 42L, Prop3 = Guid.NewGuid() }; + + dynamic tTest = new DynamicObjects.Get(tAnon); + + Assert.That(tAnon.Prop1, Is.EqualTo(tTest.Prop1)); + Assert.That(tAnon.Prop2, Is.EqualTo(tTest.Prop2)); + Assert.That(tAnon.Prop3, Is.EqualTo(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.That(tArray[2].ToString(), Is.EqualTo(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.That(tSet, Is.True); + } + + [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.That(tSet, Is.False); + } + + [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.That(tNew.Prop1, Is.EqualTo(tTest.Prop1)); + Assert.That(tNew.Prop2, Is.EqualTo(tTest.Prop2)); + Assert.That(tNew.Prop3, Is.EqualTo(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.That(tAnon.Prop1, Is.EqualTo(tTest.Prop1)); + Assert.That(tAnon.Prop2, Is.EqualTo(tTest.Prop2)); + Assert.That(tAnon.Prop3, Is.EqualTo(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.That(tFwd.Create(99).Value, Is.EqualTo("test99")); + } + + [Test] + public void ForwardDynamicTest() + { + dynamic tNew = new ExpandoObject(); + tNew.Prop1 = "Test"; + tNew.Prop2 = 42L; + tNew.Prop3 = Guid.NewGuid(); + + dynamic tTest = new TestForwarder(tNew); + + Assert.That(tNew.Prop1, Is.EqualTo(tTest.Prop1)); + Assert.That(tNew.Prop2, Is.EqualTo(tTest.Prop2)); + Assert.That(tNew.Prop3, Is.EqualTo(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(tNew.Action3(), Is.EqualTo("test")); + Assert.That(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(tFwd.Action3(), Is.EqualTo("test")); + Assert.That(tFwd.Action4(4), Is.EqualTo("test4")); + } + + [Test] + public void DictionaryMethodsOutTest() + { + dynamic tNew = new DynamicObjects.Dictionary(); + tNew.Func = new DynamicTryString(TestOut); + + Assert.That(tNew.Func(null, "Test", out string tOut), Is.True); + Assert.That(tOut, Is.EqualTo("Test")); + + Assert.That(tNew.Func(null, 1, out string tOut2), Is.False); + Assert.That(tOut2, Is.Null); + } + + 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.That(tNew.Action3(), Is.EqualTo("Cat-test")); + } + + [Test] + public void DictionaryNullMethodsTest() + { + dynamic tNew = new DynamicObjects.Dictionary(); + Dynamic.ApplyEquivalentType(tNew, typeof(ISimpleStringMethod)); + + Assert.That(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.That(tNew.Test1, Is.EqualTo(1)); + Assert.That(tNew.Test2, Is.EqualTo(2)); + Assert.That(tNew.TestD.TestA, Is.EqualTo("A")); + Assert.That(tNew.TestD.TestB, Is.EqualTo("B")); + } + + [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.That(tDynamic, Is.EqualTo(tNotDynamic)); + + Assert.That(tDynamic.Test1, Is.EqualTo(1)); + Assert.That(tDynamic.Test2, Is.EqualTo(2L)); + Assert.That(tDynamic.Test3, Is.EqualTo(TestEnum.One)); + Assert.That(tDynamic.Test4, Is.EqualTo(TestEnum.Two)); + + Assert.That(tDynamic.TestD.TestA, Is.EqualTo("A")); + Assert.That(tDynamic.TestD.TestB, Is.EqualTo("B")); + + Assert.That(tNotDynamic.Test1, Is.EqualTo(1)); + Assert.That(tNotDynamic.Test2, Is.EqualTo(2L)); + Assert.That(tNotDynamic.Test3, Is.EqualTo(TestEnum.One)); + Assert.That(tNotDynamic.Test4, Is.EqualTo(TestEnum.Two)); + + Assert.That(tNotDynamic.TestD.GetType(), Is.EqualTo(typeof(Dictionary))); + Assert.That(tDynamic.TestD.GetType(), Is.EqualTo(typeof(DynamicObjects.Dictionary))); + } + + [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.That(tDynamic, Is.EqualTo(tNotDynamic)); + Assert.That(tDynamic, Is.EqualTo(tDictionary)); + Assert.That(tNotDynamic, Is.EqualTo(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.That(tDyn.Test1, Is.EqualTo(1)); + Assert.That(tDyn.Test2, Is.EqualTo("2")); + Assert.That(tDyn.IsGreaterThan5(6), Is.True); + Assert.That(tDyn.IsGreaterThan5(4), Is.False); + + Assert.That(tData.Count, Is.EqualTo(1)); + tDyn.ClearData(); + Assert.That(tData.Count, Is.EqualTo(0)); + } + + [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.That(tInterface.Count, Is.EqualTo(10)); + Assert.That(tInterface.IsSynchronized, Is.False); + Assert.That(tInterface.SyncRoot, Is.EqualTo(this)); + Assert.That(tInterface.GetEnumerator(), Is.InstanceOf()); + } + + [Test] + public void TestBuilder() + { + var New = Builder.New(); + + var tExpando = New.Object( + Test: "test1", + Test2: "Test 2nd" + ); + Assert.That(tExpando.Test, Is.EqualTo("test1")); + Assert.That(tExpando.Test2, Is.EqualTo("Test 2nd")); + + dynamic NewD = new DynamicObjects.Builder(); + + var tExpandoNamedTest = NewD.Robot( + LeftArm: "Rise", + RightArm: "Clamp" + ); + + Assert.That(tExpandoNamedTest.LeftArm, Is.EqualTo("Rise")); + Assert.That(tExpandoNamedTest.RightArm, Is.EqualTo("Clamp")); + } + + [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.That(tExpando.LeftArm, Is.EqualTo("Rise")); + Assert.That(tExpando.RightArm, Is.EqualTo("Clamp")); + Assert.That(tExpando.GetType(), Is.EqualTo(typeof(ExpandoObject))); + + Assert.That(tDict.LeftArm, Is.EqualTo("RiseD")); + Assert.That(tDict.RightArm, Is.EqualTo("ClampD")); + Assert.That(tDict.GetType(), Is.EqualTo(typeof(DynamicObjects.Dictionary))); + } + + [Test] + public void TestClayFactorySyntax() + { + dynamic New = Builder.New(); + + { + var person = New.Person(); + person.FirstName = "Louis"; + person.LastName = "Dejardin"; + Assert.That(person.FirstName, Is.EqualTo("Louis")); + Assert.That(person.LastName, Is.EqualTo("Dejardin")); + } + { + var person = New.Person(); + person["FirstName"] = "Louis"; + person["LastName"] = "Dejardin"; + Assert.That(person.FirstName, Is.EqualTo("Louis")); + Assert.That(person.LastName, Is.EqualTo("Dejardin")); + } + { + var person = New.Person( + FirstName: "Bertrand", + LastName: "Le Roy" + ).Aliases("bleroy", "boudin"); + + Assert.That(person.FirstName, Is.EqualTo("Bertrand")); + Assert.That(person.LastName, Is.EqualTo("Le Roy")); + Assert.That(person.Aliases[1], Is.EqualTo("boudin")); + } + { + var person = New.Person() + .FirstName("Louis") + .LastName("Dejardin") + .Aliases(new[] { "Lou" }); + + Assert.That(person.FirstName, Is.EqualTo("Louis")); + Assert.That(person.Aliases[0], Is.EqualTo("Lou")); + } + { + var person = New.Person(new + { + FirstName = "Louis", + LastName = "Dejardin" + }); + Assert.That(person.FirstName, Is.EqualTo("Louis")); + Assert.That(person.LastName, Is.EqualTo("Dejardin")); + } + } + + [Test] + 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.That(people[0].LastName, Is.EqualTo("Dejardin")); + Assert.That(people[1].LastName, Is.EqualTo("Le Roy")); + + var people2 = new DynamicObjects.List + { + New.Robot(Name: "Bender"), + New.Robot(Name: "RobotDevil") + }; + + Assert.That(people2[0].Name, Is.EqualTo("Bender")); + Assert.That(people2[1].Name, Is.EqualTo("RobotDevil")); + } + + [Test] + public void TestQuicListSyntax() + { + var tList = Build.NewList("test", "one", "two"); + Assert.That(tList[1], Is.EqualTo("one")); + + var tList2 = Build.NewList("test", "one", "two", "three"); + Assert.That(tList2[3], Is.EqualTo("three")); + } + + [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.That(tVar.Test, Is.EqualTo("One")); + Assert.That(tVar.Test2, Is.EqualTo(2)); + Assert.That(tVar.NameLast, Is.EqualTo("Watson")); + } #if !NET6_0_OR_GREATER [Test] public void TestCodeDomLateTypeBind() - { + { // http://stackoverflow.com/questions/16918612/dynamically-use-runtime-compiled-assemlby/16920438#16920438 string code = @" namespace CodeInjection @@ -580,55 +516,43 @@ public static string Concatenate(string s1, string s2){ } } }"; - + var codeProvider = new CSharpCodeProvider(); - - var parameters = new CompilerParameters {GenerateExecutable = false, GenerateInMemory = true}; - CompilerResults cr = codeProvider.CompileAssemblyFromSource(parameters,code); + 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"))); - + Assert.That(DynConcatenateString.Concatenate("1", "2"), Is.EqualTo("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"); +#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.That(two.IsEven, Is.True); + + var tParsed = tBigIntType.Parse("4"); + + Assert.That(tParsed.IsEven, Is.True); + } + else + { + Assert.Fail("Big Int Didn't Load"); + } + } + } } diff --git a/Tests/ExpandoObjs.cs b/Tests/ExpandoObjs.cs index 78f15ee..f264892 100644 --- a/Tests/ExpandoObjs.cs +++ b/Tests/ExpandoObjs.cs @@ -1,58 +1,57 @@ using System.Dynamic; +using NUnit.Framework; namespace Dynamitey.Tests { - [TestFixture] - public class ExpandoObjs - { - [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()); - } - } + [TestFixture] + public class ExpandoObjs + { + [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.That(tExpandoNew.Test, Is.EqualTo("test1")); + Assert.That(tExpandoNew.Test2, Is.EqualTo("Test 2nd")); + + Assert.That(tExpando.Test, Is.EqualTo(tExpandoNew.Test)); + Assert.That(tExpando.Test2, Is.EqualTo(tExpandoNew.Test2)); + Assert.That(tExpando.GetType(), Is.EqualTo(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.That(tExpandoNamedTestShortcut.LeftArm, Is.EqualTo("Rise")); + Assert.That(tExpandoNamedTestShortcut.RightArm, Is.EqualTo("Clamp")); + + Assert.That(tExpandoNamedTest.LeftArm, Is.EqualTo(tExpandoNamedTestShortcut.LeftArm)); + Assert.That(tExpandoNamedTest.RightArm, Is.EqualTo(tExpandoNamedTestShortcut.RightArm)); + Assert.That(tExpandoNamedTest.GetType(), Is.EqualTo(tExpandoNamedTestShortcut.GetType())); + } + } } diff --git a/Tests/Impromptu.cs b/Tests/Impromptu.cs index 31e0d89..d0027a4 100644 --- a/Tests/Impromptu.cs +++ b/Tests/Impromptu.cs @@ -14,7 +14,7 @@ public void DictionaryInterfaceNullMethodsTest() dynamic tNew = new DynamicObjects.Dictionary(); ISimpleStringMethod tActsLike = ImpromptuInterface.Impromptu.ActLike(tNew); - Assert.AreEqual(false, tActsLike.StartsWith("Te")); + Assert.That(tActsLike.StartsWith("Te"), Is.EqualTo(false)); } [Test] @@ -55,7 +55,7 @@ public void PropertySpecTest() if (baseObj.TryTypeForName("test", out Type ot)) { - Assert.AreEqual(typeof(bool), ot); + Assert.That(ot, Is.EqualTo(typeof(bool))); } else { @@ -71,7 +71,7 @@ public void InterfaceSpecTest() if (baseObj.TryTypeForName("Prop2", out Type ot)) { - Assert.AreEqual(typeof(long), ot); + Assert.That(ot, Is.EqualTo(typeof(long))); } else { @@ -83,7 +83,7 @@ public void InterfaceSpecTest() public void DictionaryCurriedAcctlikeNullMethodsTest() { ISimpleStringMethod tActsLike = Interfacing << new DynamicObjects.Dictionary(); - Assert.AreEqual(false, tActsLike.StartsWith("Te")); + Assert.That(tActsLike.StartsWith("Te"), Is.EqualTo(false)); } public interface IBuilder @@ -122,8 +122,8 @@ public void TestBuilderActLikeAnon() }) }); - Assert.AreEqual("Lvl1", tNest.NameLevel1); - Assert.AreEqual("Lvl2", tNest.Nested.NameLevel2); + Assert.That(tNest.NameLevel1, Is.EqualTo("Lvl1")); + Assert.That(tNest.Nested.NameLevel2, Is.EqualTo("Lvl2")); } [Test] @@ -138,8 +138,8 @@ public void TestBuilderActLikeNamed() ) ); - Assert.AreEqual("Lvl1", tNest.NameLevel1); - Assert.AreEqual("Lvl2", tNest.Nested.NameLevel2); + Assert.That(tNest.NameLevel1, Is.EqualTo("Lvl1")); + Assert.That(tNest.Nested.NameLevel2, Is.EqualTo("Lvl2")); } } } diff --git a/Tests/Invoke.cs b/Tests/Invoke.cs index c2778c4..38f45c0 100644 --- a/Tests/Invoke.cs +++ b/Tests/Invoke.cs @@ -1,1471 +1,1092 @@ -using System.Drawing; +using System; +using System.Collections.Generic; using System.Dynamic; using System.Linq.Expressions; using System.Xml.Linq; using Dynamitey.SupportLibrary; using Microsoft.CSharp.RuntimeBinder; using Moq; +using NUnit.Framework; using System.Globalization; +using System.Drawing; namespace Dynamitey.Tests { - public class Invoke - { - [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); - Dynamic.InvokeUnaryOpartor(type,mock); - } - - [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); - } - - } + public class Invoke + { + [OneTimeTearDown] + public void DestroyCaches() + { + Dynamic.ClearCaches(); + } + + [Test] + public void TestDynamicSet() + { + dynamic tExpando = new ExpandoObject(); + var tSetValue = "1"; + Dynamic.InvokeSet(tExpando, "Test", tSetValue); + Assert.That(tExpando.Test, Is.EqualTo(tSetValue)); + } + + [Test] + public void TestPocoSet() + { + var tPoco = new PropPoco(); + var tSetValue = "1"; + Dynamic.InvokeSet(tPoco, "Prop1", tSetValue); + Assert.That(tPoco.Prop1, Is.EqualTo(tSetValue)); + } + + [Test] + public void TestStructSet() + { + object tPoco = new PropStruct(); + var tSetValue = "1"; + Dynamic.InvokeSet(tPoco, "Prop1", tSetValue); + Assert.That(((PropStruct)tPoco).Prop1, Is.EqualTo(tSetValue)); + } + + [Test] + public void TestCacheableDyanmicSetAndPocoSetAndSetNull() + { + dynamic tExpando = new ExpandoObject(); + var tSetValueD = "4"; + + var tCachedInvoke = new CacheableInvocation(InvocationKind.Set, "Prop1"); + tCachedInvoke.Invoke((object)tExpando, tSetValueD); + + Assert.That(tExpando.Prop1, Is.EqualTo(tSetValueD)); + + var tPoco = new PropPoco(); + var tSetValue = "1"; + + tCachedInvoke.Invoke(tPoco, tSetValue); + Assert.That(tPoco.Prop1, Is.EqualTo(tSetValue)); + + string tSetValue2 = null; + tCachedInvoke.Invoke(tPoco, tSetValue2); + Assert.That(tPoco.Prop1, Is.EqualTo(tSetValue2)); + } + + [Test] + public void TestConvert() + { + var tEl = new XElement("Test", "45"); + var tCast = Dynamic.InvokeConvert(tEl, typeof(int), @explicit: true); + Assert.That(tCast.GetType(), Is.EqualTo(typeof(int))); + Assert.That(tCast, Is.EqualTo(45)); + } + + [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.That(tCast.GetType(), Is.EqualTo(typeof(int))); + Assert.That(tCast, Is.EqualTo(45)); + } + + [Test] + public void TestConstruct() + { + var tCast = Dynamic.InvokeConstructor(typeof(List), new object[] + { + new string[] { "one", "two", "three" } + }); + Assert.That(tCast[1], Is.EqualTo("two")); + } + + [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.That(tCast[1], Is.EqualTo("two")); + } + + [Test] + public void TestConstructOptional() + { + var argname = InvokeArg.Create; + PocoOptConstructor tCast = Dynamic.InvokeConstructor(typeof(PocoOptConstructor), argname("three", "3")); + Assert.That(tCast.One, Is.EqualTo("-1")); + Assert.That(tCast.Two, Is.EqualTo("-2")); + Assert.That(tCast.Three, Is.EqualTo("3")); + } + + [Test] + public void TestCacheableConstructOptional() + { + var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor, argCount: 1, argNames: new[] { "three" }); + var tCast = (PocoOptConstructor)tCachedInvoke.Invoke(typeof(PocoOptConstructor), "3"); + Assert.That(tCast.One, Is.EqualTo("-1")); + Assert.That(tCast.Two, Is.EqualTo("-2")); + Assert.That(tCast.Three, Is.EqualTo("3")); + } + + [Test] + public void TestOptionalArgumentActivationNoneAndCacheable() + { + Assert.Throws(() => Activator.CreateInstance()); + + var tList = Dynamic.InvokeConstructor(typeof(DynamicObjects.List)); + Assert.That(tList.GetType(), Is.EqualTo(typeof(DynamicObjects.List))); + + var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor); + var tList1 = tCachedInvoke.Invoke(typeof(DynamicObjects.List)); + Assert.That(tList1.GetType(), Is.EqualTo(typeof(DynamicObjects.List))); + } + + [Test] + public void TestConstructValueType() + { + var tCast = Dynamic.InvokeConstructor(typeof(DateTime), 2009, 1, 20); + Assert.That(tCast.Day, Is.EqualTo(20)); + } + + [Test] + public void TestCacheableConstructValueType() + { + var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor, argCount: 3); + dynamic tCast = tCachedInvoke.Invoke(typeof(DateTime), 2009, 1, 20); + Assert.That(tCast.Day, Is.EqualTo(20)); + } + + [Test] + public void TestConstructValueTypeJustDynamic() + { + dynamic day = 20; + dynamic year = 2009; + dynamic month = 1; + var tCast = new DateTime(year, month, day); + DateTime tDate = tCast; + Assert.That(tDate.Day, Is.EqualTo(20)); + } + + [Test] + public void TestConstructprimativetype() + { + var tCast = Dynamic.InvokeConstructor(typeof(Int32)); + Assert.That(tCast, Is.EqualTo(default(Int32))); + } + + [Test] + public void TestConstructDateTimeNoParams() + { + var tCast = Dynamic.InvokeConstructor(typeof(DateTime)); + Assert.That(tCast, Is.EqualTo(default(DateTime))); + } + + [Test] + public void TestConstructOBjectNoParams() + { + var tCast = Dynamic.InvokeConstructor(typeof(object)); + Assert.That(tCast.GetType(), Is.EqualTo(typeof(object))); + } + + [Test] + public void TestConstructNullableprimativetype() + { + var tCast = Dynamic.InvokeConstructor(typeof(Nullable)); + Assert.That(tCast, Is.EqualTo(null)); + } + + [Test] + public void TestConstructGuid() + { + var tCast = Dynamic.InvokeConstructor(typeof(Guid)); + Assert.That(tCast, Is.EqualTo(default(Guid))); + } + + [Test] + public void TestCacheablePrimativeDateTimeObjectNullableAndGuidNoParams() + { + var tCachedInvoke = new CacheableInvocation(InvocationKind.Constructor); + + dynamic tCast = tCachedInvoke.Invoke(typeof(Int32)); + Assert.That(tCast, Is.EqualTo(default(Int32))); + + tCast = tCachedInvoke.Invoke(typeof(DateTime)); + Assert.That(tCast, Is.EqualTo(default(DateTime))); + + tCast = tCachedInvoke.Invoke(typeof(List)); + Assert.That(tCast.GetType(), Is.EqualTo(typeof(List))); + + tCast = tCachedInvoke.Invoke(typeof(object)); + Assert.That(tCast.GetType(), Is.EqualTo(typeof(object))); + + tCast = tCachedInvoke.Invoke(typeof(Nullable)); + Assert.That(tCast, Is.EqualTo(null)); + + tCast = tCachedInvoke.Invoke(typeof(Guid)); + Assert.That(tCast, Is.EqualTo(default(Guid))); + } + + [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.That(tOut, Is.EqualTo(false)); + } + + [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.That(tOut, Is.EqualTo(false)); + } + + 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.That(tOut, Is.EqualTo(42)); + } + + [Test] + public void TestImplicitConvert() + { + var tEl = 45; + var tCast = Dynamic.InvokeConvert(tEl, typeof(long)); + Assert.That(tCast.GetType(), Is.EqualTo(typeof(long))); + } + + [Test] + public void TestCoerceConverterColor() + { + var colorString = "PaleVioletRed"; + var color = Dynamic.CoerceConvert(colorString, typeof(Color)); + Assert.That(color, Is.TypeOf()); + Assert.That(color, Is.EqualTo(Color.PaleVioletRed)); + } + + [Test] + public void TestCoerceConverterDBNULL() + { + var tEl = DBNull.Value; + var tCast = Dynamic.CoerceConvert(tEl, typeof(long)); + Assert.That(tCast.GetType(), Is.EqualTo(typeof(long))); + + var tCast2 = Dynamic.CoerceConvert(tEl, typeof(string)); + Assert.That(tCast2, Is.EqualTo(null)); + Assert.AreNotEqual(null, tEl); + } + + [Test] + public void TestCacheableImplicitConvert() + { + var tEl = 45; + var tCachedInvoke = CacheableInvocation.CreateConvert(typeof(long)); + var tCast = tCachedInvoke.Invoke(tEl); + Assert.That(tCast.GetType(), Is.EqualTo(typeof(long))); + } + + [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.That(tOut, Is.EqualTo(tSetValue)); + + var tSetValue2 = "2"; + tAnon = new PropPoco { Prop1 = tSetValue2 }; + var tOut2 = tCached.Invoke(tAnon); + Assert.That(tOut2, Is.EqualTo(tSetValue2)); + } + + [Test] + public void TestGetIndexer() + { + dynamic tSetValue = "1"; + var tAnon = new[] { tSetValue, "2" }; + string tOut = Dynamic.InvokeGetIndex(tAnon, 0); + Assert.That(tOut, Is.EqualTo(tSetValue)); + } + + [Test] + public void TestGetIndexerValue() + { + var tAnon = new int[] { 1, 2 }; + int tOut = Dynamic.InvokeGetIndex(tAnon, 1); + Assert.That(tOut, Is.EqualTo(tAnon[1])); + } + + [Test] + public void TestGetLengthArray() + { + var tAnon = new[] { "1", "2" }; + int tOut = Dynamic.InvokeGet(tAnon, "Length"); + Assert.That(tOut, Is.EqualTo(2)); + } + + [Test] + public void TestGetIndexerArray() + { + dynamic tSetValue = "1"; + var tAnon = new List { tSetValue, "2" }; + string tOut = Dynamic.InvokeGetIndex(tAnon, 0); + Assert.That(tOut, Is.EqualTo(tSetValue)); + } + + [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.That(tOut, Is.EqualTo(tStrings[0])); + + var tOut2 = (string)tCachedInvoke.Invoke(tStrings, 1); + Assert.That(tOut2, Is.EqualTo(tStrings[1])); + + var tInts = new int[] { 3, 4 }; + var tOut3 = (int)tCachedInvoke.Invoke(tInts, 0); + Assert.That(tOut3, Is.EqualTo(tInts[0])); + + var tOut4 = (int)tCachedInvoke.Invoke(tInts, 1); + Assert.That(tOut4, Is.EqualTo(tInts[1])); + + var tList = new List { "5", "6" }; + var tOut5 = (string)tCachedInvoke.Invoke(tList, 0); + Assert.That(tOut5, Is.EqualTo(tList[0])); + + var tOut6 = (string)tCachedInvoke.Invoke(tList, 0); + Assert.That(tOut6, Is.EqualTo(tList[0])); + } + + [Test] + public void TestSetIndexer() + { + dynamic tSetValue = "3"; + var tAnon = new List { "1", "2" }; + Dynamic.InvokeSetIndex(tAnon, 0, tSetValue); + Assert.That(tAnon[0], Is.EqualTo(tSetValue)); + } + + [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.That(tList[0], Is.EqualTo(tSetValue)); + } + + [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.That(tOut, Is.EqualTo(tValue.ToString())); + } + + [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.That(tOut, Is.EqualTo(tValue.ToString())); + } + + [Test] + public void TestMethodStaticOverloadingPassAndGetValue() + { + var tPoco = new OverloadingMethPoco(); + var tValue = 1; + var tOut = Dynamic.InvokeMember(tPoco, "Func", tValue); + Assert.That(tOut, Is.EqualTo("int")); + Assert.That((object)tOut, Is.EqualTo("int")); //should still be int because this uses runtime type + + var tOut2 = Dynamic.InvokeMember(tPoco, "Func", 1m); + Assert.That(tOut2, Is.EqualTo("object")); + + var tOut3 = Dynamic.InvokeMember(tPoco, "Func", new { Anon = 1 }); + Assert.That(tOut3, Is.EqualTo("object")); + } + + [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.That(tOut, Is.EqualTo("int")); + Assert.That((object)tOut, Is.EqualTo("int")); //should still be int because this uses runtime type + + var tOut2 = tCachedInvoke.Invoke(tPoco, 1m); + Assert.That(tOut2, Is.EqualTo("object")); + + var tOut3 = tCachedInvoke.Invoke(tPoco, new { Anon = 1 }); + Assert.That(tOut3, Is.EqualTo("object")); + } + + [Test] + public void TestMethodPocoOverloadingPassAndGetValueArg() + { + var tPoco = new OverloadingMethPoco(); + var tValue = 1; + var tOut = Dynamic.InvokeMember(tPoco, "Func", new InvokeArg("arg", tValue)); + Assert.That(tOut, Is.EqualTo("int")); + Assert.That((object)tOut, Is.EqualTo("int")); //should still be int because this uses runtime type + + var tOut2 = Dynamic.InvokeMember(tPoco, "Func", 1m); + Assert.That(tOut2, Is.EqualTo("object")); + + var tOut3 = Dynamic.InvokeMember(tPoco, "Func", new { Anon = 1 }); + Assert.That(tOut3, Is.EqualTo("object")); + } + + [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.That(tOut, Is.EqualTo("object named")); + Assert.That((object)tOut, Is.EqualTo("object named")); + } + + [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.That(tOut, Is.EqualTo("object named")); + Assert.That((object)tOut, Is.EqualTo("object named")); + } + + [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.That(tOut, Is.EqualTo("object named")); + Assert.That((object)tOut, Is.EqualTo("object named")); + } + + [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.That(tOut, Is.EqualTo("object named")); + Assert.That((object)tOut, Is.EqualTo("object named")); + } + + [Test] + public void TestMethodPocoOverloadingPassAndGetValueNull() + { + var tPoco = new OverloadingMethPoco(); + var tValue = 1; + var tOut = Dynamic.InvokeMember(tPoco, "Func", tValue); + Assert.That(tOut, Is.EqualTo("int")); + Assert.That((object)tOut, Is.EqualTo("int")); //should still be int because this uses runtime type + + var tOut2 = Dynamic.InvokeMember(tPoco, "Func", 1m); + Assert.That(tOut2, Is.EqualTo("object")); + + var tOut3 = Dynamic.InvokeMember(tPoco, "Func", null); + Assert.That(tOut3, Is.EqualTo("object")); + + var tOut4 = Dynamic.InvokeMember(tPoco, "Func", null, null, "test", null, null, null); + Assert.That(tOut4, Is.EqualTo("object 6")); + + var tOut5 = Dynamic.InvokeMember(tPoco, "Func", null, null, null, null, null, null); + Assert.That(tOut5, Is.EqualTo("object 6")); + } + + /// + /// 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.That(tResult, Is.EqualTo("success")); + } + + [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.That(tTest, Is.EqualTo(tValue)); + } + + [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.That(tTest, Is.EqualTo(tValue)); + } + + [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.That(tTest, Is.EqualTo(tValue)); + + var tCachedInvoke2 = new CacheableInvocation(InvocationKind.InvokeMemberUnknown, "Func", argCount: 1); + var Test2 = tCachedInvoke2.Invoke((object)tExpando, tValue); + Assert.That(Test2, Is.EqualTo(tValue)); + } + + [Test] + public void TestMethodPocoGetValue() + { + var tValue = 1; + var tOut = Dynamic.InvokeMember(tValue, "ToString"); + Assert.That(tOut, Is.EqualTo(tValue.ToString())); + } + + [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.That(tOut, Is.EqualTo(tExpected)); + } + + [Test] + public void TestGetDynamic() + { + var tSetValue = "1"; + dynamic tExpando = new ExpandoObject(); + tExpando.Test = tSetValue; + var tOut = Dynamic.InvokeGet(tExpando, "Test"); + Assert.That(tOut, Is.EqualTo(tSetValue)); + } + + [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.That(tOut, Is.EqualTo(tSetValue)); + } + + [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.That(tOut, Is.EqualTo(tSetValue)); + } + + [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.That(tExpando.Test.Test2.Test3, Is.EqualTo(tSetValue)); + } + + [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.That(tExpando.Test.Test2[0].Test3["Test4"], Is.EqualTo(tSetValue)); + Assert.That(tOut, Is.EqualTo(tSetValue)); + } + + [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.That(tExpando.Test.Test2.Test3, Is.EqualTo(tSetValue)); + Assert.That(tExpando.One, Is.EqualTo(1)); + Assert.That(tExpando.Two, Is.EqualTo(2)); + } + + [Test] + public void TestSetDynamicAllAnonymous() + { + dynamic tExpando = new ExpandoObject(); + Dynamic.InvokeSetAll(tExpando, new { One = 1, Two = 2, Three = 3 }); + Assert.That(tExpando.One, Is.EqualTo(1)); + Assert.That(tExpando.Two, Is.EqualTo(2)); + Assert.That(tExpando.Three, Is.EqualTo(3)); + } + + [Test] + public void TestSetDynamicAllNamed() + { + dynamic tExpando = new ExpandoObject(); + Dynamic.InvokeSetAll(tExpando, One: 1, Two: 2, Three: 3); + Assert.That(tExpando.One, Is.EqualTo(1)); + Assert.That(tExpando.Two, Is.EqualTo(2)); + Assert.That(tExpando.Three, Is.EqualTo(3)); + } + + [Test] + public void TestSetDynamicChainedOne() + { + var tSetValue = "1"; + dynamic tExpando = new ExpandoObject(); + Dynamic.InvokeSetChain(tExpando, "Test", tSetValue); + Assert.That(tExpando.Test, Is.EqualTo(tSetValue)); + } + + [Test] + public void TestGetDynamicChainedOne() + { + var tSetValue = "1"; + dynamic tExpando = new ExpandoObject(); + tExpando.Test = tSetValue; + var tOut = Dynamic.InvokeGetChain(tExpando, "Test"); + Assert.That(tOut, Is.EqualTo(tSetValue)); + } + + [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.That(tOut, Is.EqualTo(tSetValue)); + } + + [Test] + public void TestStaticGet() + { + var @static = InvokeContext.CreateStatic; + var tDate = Dynamic.InvokeGet(@static(typeof(DateTime)), "Today"); + Assert.That(tDate, Is.EqualTo(DateTime.Today)); + } + + [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.That(tDate, Is.EqualTo(DateTime.Today)); + } + + [Test] + public void TestStaticGet2() + { + var @static = InvokeContext.CreateStatic; + var tVal = Dynamic.InvokeGet(@static(typeof(StaticType)), "Test"); + Assert.That(tVal, Is.EqualTo(true)); + } + + [Test] + public void TestStaticGet3() + { + var tVal = Dynamic.InvokeGet((StaticContext)typeof(StaticType), "Test"); + Assert.That(tVal, Is.EqualTo(true)); + } + + [Test] + public void TestStaticSet() + { + var @static = InvokeContext.CreateStatic; + int tValue = 12; + Dynamic.InvokeSet(@static(typeof(StaticType)), "TestSet", tValue); + Assert.That(StaticType.TestSet, Is.EqualTo(tValue)); + } + + [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.That(StaticType.TestSet, Is.EqualTo(tValue)); + } + + [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.That(tDate, Is.EqualTo(new DateTime(2009, 1, 20))); + } + + [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.That(tDate, Is.EqualTo(new DateTime(2009, 1, 20))); + } + + [Test] + public void TestIsEvent() + { + dynamic tPoco = new PocoEvent(); + var tResult = Dynamic.InvokeIsEvent(tPoco, "Event"); + Assert.That(tResult, Is.EqualTo(true)); + } + + [Test] + public void TestCacheableIsEventAndIsNotEvent() + { + object tPoco = new PocoEvent(); + var tCachedInvoke = new CacheableInvocation(InvocationKind.IsEvent, "Event"); + var tResult = tCachedInvoke.Invoke(tPoco); + Assert.That(tResult, Is.EqualTo(true)); + + dynamic tDynamic = new DynamicObjects.Dictionary(); + tDynamic.Event = null; + var tResult2 = tCachedInvoke.Invoke((object)tDynamic); + Assert.That(tResult2, Is.EqualTo(false)); + } + + [Test] + public void TestIsNotEvent() + { + dynamic tDynamic = new DynamicObjects.Dictionary(); + tDynamic.Event = null; + var tResult = Dynamic.InvokeIsEvent(tDynamic, "Event"); + Assert.That(tResult, Is.EqualTo(false)); + + bool tTest = false; + bool tTest2 = false; + tDynamic.Event += new EventHandler((@object, args) => { tTest = true; }); + tDynamic.Event += new EventHandler((@object, args) => { tTest2 = true; }); + Assert.That(tTest, Is.EqualTo(false)); + Assert.That(tTest2, Is.EqualTo(false)); + + tDynamic.Event(null, null); + Assert.That(tTest, Is.EqualTo(true)); + Assert.That(tTest2, Is.EqualTo(true)); + } + + [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.That(tTest, Is.EqualTo(true)); + + var tPoco2 = new PropPoco() { Prop2 = 3 }; + Dynamic.InvokeAddAssignMember(tPoco2, "Prop2", 4); + Assert.That(tPoco2.Prop2, Is.EqualTo(7L)); + } + + [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.That(tTest, Is.EqualTo(true)); + + var tPoco2 = new PropPoco() { Event = 3 }; + tCachedInvoke.Invoke(tPoco2, 4); + Assert.That(tPoco2.Event, Is.EqualTo(7L)); + } + + [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.That(tTest, Is.EqualTo(false)); + + Dynamic.InvokeSubtractAssignMember(tPoco, "Event", tEvent); // Test Second Time + + var tPoco2 = new PropPoco() { Prop2 = 3 }; + Dynamic.InvokeSubtractAssignMember(tPoco2, "Prop2", 4); + Assert.That(tPoco2.Prop2, Is.EqualTo(-1L)); + } + + [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.That(tTest, Is.EqualTo(false)); + tCachedInvoke.Invoke(tPoco, tEvent); // Test Second Time + + var tPoco2 = new PropPoco() { Event = 3 }; + tCachedInvoke.Invoke(tPoco2, 4); + Assert.That(tPoco2.Event, Is.EqualTo(-1)); + } + + [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.That(tTest, Is.EqualTo(true)); + Dynamic.InvokeAddAssignMember(tDyanmic, "Prop2", 4); + Assert.That(tDyanmic.Prop2, Is.EqualTo(7L)); + } + + [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.That(tTest, Is.EqualTo(true)); + tCachedInvoke.Invoke((object)tDynamic2, 4); + Assert.That(tDynamic2.Event, Is.EqualTo(7)); + } + + [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.That(tTest, Is.EqualTo(false)); + Dynamic.InvokeSubtractAssignMember(tDyanmic, "Prop2", 4); + Assert.That(tDyanmic.Prop2, Is.EqualTo(-1L)); + } + + [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.That(tTest, Is.EqualTo(false)); + tCachedInvoke.Invoke((object)tDynamic2, 4); + Assert.That(tDynamic2.Event, Is.EqualTo(-1)); + } + + [Test] + public void TestDynamicMemberNamesExpando() + { + ExpandoObject tExpando = Build.NewObject(One: 1); + Assert.That(Dynamic.GetMemberNames(tExpando, dynamicOnly: true).Single(), Is.EqualTo("One")); + } + + [Test] + public void TestDynamicMemberNamesImpromput() + { + DynamicObjects.Dictionary tDict = Build.NewObject(Two: 2); + Assert.That(Dynamic.GetMemberNames(tDict, dynamicOnly: true).Single(), Is.EqualTo("Two")); + } + + [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.That(tCachedIvnocation1.GetHashCode(), Is.EqualTo(tCachedIvnocation2.GetHashCode())); + Assert.That(tCachedIvnocation1, Is.EqualTo(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.That(binder.Operation, Is.EqualTo(_type)); + result = _type; + return true; + } + + public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) + { + Assert.That(binder.Operation, Is.EqualTo(_type)); + 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); + Dynamic.InvokeUnaryOpartor(type, mock); + } + + [Test] + public void TestInvokeAdd() + { + Assert.That(Dynamic.InvokeBinaryOperator(1, ExpressionType.Add, 2), Is.EqualTo(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.That(Dynamic.InvokeBinaryOperator(1, ExpressionType.Subtract, 2), Is.EqualTo(-1)); + } + } } diff --git a/Tests/Linq.cs b/Tests/Linq.cs index 13132a2..1864a85 100644 --- a/Tests/Linq.cs +++ b/Tests/Linq.cs @@ -16,7 +16,7 @@ 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); + Assert.That(expected, Is.EqualTo(actual)); } [Test] public void MoreGenericsDynamicLinq() @@ -26,7 +26,7 @@ public void MoreGenericsDynamicLinq() .Select(new Func>(i => Tuple.Create(1, i))) .Aggregate(0, new Func, int>((accum, each) => each.Item2)); - Assert.AreEqual(expected, actual); + Assert.That(expected, Is.EqualTo(actual)); } @@ -61,7 +61,7 @@ private dynamic RunPythonHelper(object linq, string code) //result = linq.OfType[System.Int32]().Skip(1).First() //"); -// Assert.AreEqual(expected, actual); +// Assert.That(expected, actual); // } @@ -78,7 +78,7 @@ private dynamic RunPythonHelper(object linq, string code) //"); -// Assert.AreEqual(expected, actual); +// Assert.That(expected, actual); // } @@ -134,10 +134,10 @@ 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()); + && HelperSingleGenericArgMatch(it.GetParameters().First().ParameterType.GetGenericArguments().Single()); } - bool HelperSignleGenericArgMatch(Type info) + bool HelperSingleGenericArgMatch(Type info) { foreach (var name in new[] { "TSource", "TFirst", "TOuter" }) { @@ -154,7 +154,7 @@ bool HelperSignleGenericArgMatch(Type info) // Define other methods and classes here string HelperFormatType(Type it) { - if (HelperSignleGenericArgMatch(it)) + if (HelperSingleGenericArgMatch(it)) { return "TSource"; } @@ -171,7 +171,7 @@ string HelperFormatType(Type it) string HelperGenericParams(Type[] it) { - var tArgs = it.Where(t => !HelperSignleGenericArgMatch(t)).Select(t => HelperFormatType(t)); + var tArgs = it.Where(t => !HelperSingleGenericArgMatch(t)).Select(t => HelperFormatType(t)); if (!tArgs.Any()) { return ""; diff --git a/Tests/MimicTest.cs b/Tests/MimicTest.cs index 4da5d78..42cfc44 100644 --- a/Tests/MimicTest.cs +++ b/Tests/MimicTest.cs @@ -150,7 +150,7 @@ public void Inheritance_Int() { dynamic mimic = new SubMimic(); int result = mimic.Add(2, 2); - Assert.AreEqual(4, result); + Assert.That(4, Is.EqualTo(result)); } [Test] @@ -158,7 +158,7 @@ public void Inheritance_String() { dynamic mimic = new SubMimic(); string result = mimic.Add("He", "llo"); - Assert.AreEqual("Hello", result); + Assert.That("Hello", Is.EqualTo(result)); } [Test] @@ -166,7 +166,7 @@ public void Inheritance_No_Match() { dynamic mimic = new SubMimic(); int result = mimic.Add(1, "llo"); - Assert.AreEqual(default(int), result); + Assert.That(default(int), Is.EqualTo(result)); } } } From 7b5e1932107a8230c5f5ca2c902c5ef33ce4306c Mon Sep 17 00:00:00 2001 From: Tom Atwood Date: Tue, 6 Aug 2024 18:26:46 -0400 Subject: [PATCH 2/2] feature/#40: Code cleanup with CodeMaid. --- Dynamitey/Builder.cs | 380 ++-- Dynamitey/CacheableInvocation.cs | 617 ++--- Dynamitey/Dynamic.cs | 1993 ++++++++--------- Dynamitey/DynamicObjects/BaseDictionary.cs | 651 +++--- Dynamitey/DynamicObjects/BaseForwarder.cs | 818 ++++--- Dynamitey/DynamicObjects/BaseObject.cs | 158 +- Dynamitey/DynamicObjects/Builder.cs | 833 ++++--- Dynamitey/DynamicObjects/Dictionary.cs | 216 +- Dynamitey/DynamicObjects/Dummy.cs | 164 +- .../ExtensionToInstanceProxy.cs | 835 ++++--- Dynamitey/DynamicObjects/Factory.cs | 200 +- Dynamitey/DynamicObjects/FauxType.cs | 518 +++-- .../DynamicObjects/FluentStringLookup.cs | 99 +- Dynamitey/DynamicObjects/Get.cs | 223 +- Dynamitey/DynamicObjects/LateType.cs | 291 ++- Dynamitey/DynamicObjects/Lazy.cs | 151 +- Dynamitey/DynamicObjects/LinqInstanceProxy.cs | 507 +++-- Dynamitey/DynamicObjects/List.cs | 778 ++++--- Dynamitey/DynamicObjects/Mimic.cs | 285 ++- Dynamitey/DynamicObjects/Recorder.cs | 258 ++- Dynamitey/DynamicObjects/RegexMatch.cs | 259 ++- Dynamitey/Expando.cs | 47 +- Dynamitey/FluentRegex.cs | 120 +- Dynamitey/Internal/Compat/Net40.cs | 29 +- Dynamitey/Internal/Curry.cs | 220 +- Dynamitey/Internal/InvokeSetters.cs | 174 +- .../Internal/Optimization/BareBonesList.cs | 200 +- Dynamitey/Internal/Optimization/BinderHash.cs | 301 ++- .../Optimization/InvokeHelper-Regular.cs | 1615 +++++++------ Dynamitey/Internal/Optimization/Util.cs | 375 ++-- Dynamitey/Invocation.cs | 542 ++--- Dynamitey/InvokeArg.cs | 134 +- Dynamitey/InvokeContext.cs | 216 +- Dynamitey/InvokeMemberName.cs | 265 ++- Dynamitey/PartialApply.cs | 356 ++- Dynamitey/Tupler.cs | 398 ++-- SupportLibrary/SupportTypes.cs | 958 ++++---- Tests/Curry.cs | 5 +- Tests/DynamicObjects.cs | 8 +- Tests/ExpandoObjs.cs | 1 - Tests/Impromptu.cs | 3 +- Tests/Invoke.cs | 16 +- Tests/Linq.cs | 410 ++-- Tests/MimicTest.cs | 338 +-- Tests/PrivateTest.cs | 115 +- Tests/SpeedTest.cs | 1441 ++++++------ Tests/TimeIt.cs | 141 +- Tests/TuplerTest.cs | 286 ++- 48 files changed, 9325 insertions(+), 9623 deletions(-) diff --git a/Dynamitey/Builder.cs b/Dynamitey/Builder.cs index 75f724d..b16f386 100644 --- a/Dynamitey/Builder.cs +++ b/Dynamitey/Builder.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -17,194 +17,186 @@ 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; - } - } - - + /// + /// 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; + } + } } diff --git a/Dynamitey/CacheableInvocation.cs b/Dynamitey/CacheableInvocation.cs index 9fa74e2..a7c8a09 100644 --- a/Dynamitey/CacheableInvocation.cs +++ b/Dynamitey/CacheableInvocation.cs @@ -1,332 +1,339 @@ -using System.Dynamic; -using System.Runtime.CompilerServices; -using Dynamitey.Internal.Optimization; +using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; -using System.Reflection; using System.Collections; +using System.Dynamic; +using System.Reflection; +using System.Runtime.CompilerServices; 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; + /// + /// Cacheable representation of an invocation without the target or arguments also by default only does public methods to make it easier to cache. + /// /// - _argNames = argNames ?? new string[] {}; + 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); + } - if (storedArgs != null) - { - _argCount = storedArgs.Length; - Args = Util.GetArgsAndNames(storedArgs, out var tArgNames); - if (_argNames.Length < tArgNames.Length) - { - _argNames = tArgNames; - } - } + /// + /// 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(); - 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; - } + return new CacheableInvocation(kind, name, tArgCount, tArgNames, context); + } - 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; - } + private readonly int _argCount; + private readonly string[] _argNames; + private readonly bool _staticContext; + private readonly Type _context; + //[NonSerialized] + private CallSite _callSite; - if (context != null) - { - var dummy = context.GetTargetContext(out _context, out _staticContext); //lgtm [cs/useless-assignment-to-local] - } - else - { - _context = typeof (object); - } + //[NonSerialized] + private CallSite _callSite2; + //[NonSerialized] + private CallSite _callSite3; - } + //[NonSerialized] + private CallSite _callSite4; - /// - /// 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); - } + private readonly bool _convertExplicit; + private readonly Type _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); - } + /// + /// 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; - /// - /// 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; - } - } + _argNames = argNames ?? new string[] { }; + if (storedArgs != null) + { + _argCount = storedArgs.Length; + Args = Util.GetArgsAndNames(storedArgs, out var tArgNames); + if (_argNames.Length < tArgNames.Length) + { + _argNames = tArgNames; + } + } - /// - /// 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; - } + 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 (args == null) - { - args = new object[]{null}; - } - + 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); + } + } - 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)); - } + /// + /// 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); + } - if(args.Length > 2) - goto default; - break; - default: - throw new ArgumentException("args", - $"Incorrect number of Arguments for CachedInvocation, Expected:{_argCount}"); - } - } + /// + /// 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); + } - 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; + /// + /// 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; + } + } - } - - } - 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: - { + /// + /// 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; + } - 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; + 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)); + } - } - } - 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); - } - } + 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); + } + } + } } diff --git a/Dynamitey/Dynamic.cs b/Dynamitey/Dynamic.cs index 23550c0..ededeba 100644 --- a/Dynamitey/Dynamic.cs +++ b/Dynamitey/Dynamic.cs @@ -1,1032 +1,1007 @@ -// +// // 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 Dynamitey.Internal; +using Dynamitey.Internal.Compat; +using Dynamitey.Internal.Optimization; +using Microsoft.CSharp.RuntimeBinder; using System.Collections; using System.Dynamic; 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.That("success", Is.EqualTo(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.That(tValue.ToString(), Is.EqualTo(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.That(tValue, Is.EqualTo(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) + 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.That("success", Is.EqualTo(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.That(tValue.ToString(), Is.EqualTo(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.")] + 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.That(tValue, Is.EqualTo(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) { - 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()); - } - - - } + 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()); + } + } } diff --git a/Dynamitey/DynamicObjects/BaseDictionary.cs b/Dynamitey/DynamicObjects/BaseDictionary.cs index 65bf14f..8043f5f 100644 --- a/Dynamitey/DynamicObjects/BaseDictionary.cs +++ b/Dynamitey/DynamicObjects/BaseDictionary.cs @@ -1,351 +1,340 @@ -// +// // 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.ComponentModel; -using System.Dynamic; using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; +using System.ComponentModel; +using System.Dynamic; 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)); + /// + /// 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(); - } - } + 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(); + } + } } diff --git a/Dynamitey/DynamicObjects/BaseForwarder.cs b/Dynamitey/DynamicObjects/BaseForwarder.cs index 198cf80..8757f20 100644 --- a/Dynamitey/DynamicObjects/BaseForwarder.cs +++ b/Dynamitey/DynamicObjects/BaseForwarder.cs @@ -1,439 +1,417 @@ -// +// // 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.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; +using System.Dynamic; 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; + } - /// - /// 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); - } - - - } + /// + /// 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); + } + } } diff --git a/Dynamitey/DynamicObjects/BaseObject.cs b/Dynamitey/DynamicObjects/BaseObject.cs index 5a47a9d..7669ca9 100644 --- a/Dynamitey/DynamicObjects/BaseObject.cs +++ b/Dynamitey/DynamicObjects/BaseObject.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -18,93 +18,85 @@ 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; } + } - /// - /// 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() + { + } - /// - /// 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 + /// + /// 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; - { - /// - /// 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; + 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 NET40 || PROFILE158 case Type t: return t; #else - case TypeInfo t: - return t.UnderlyingSystemType; + 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; - } - + default: + return typeof(object); + } + }).ToList(); - FauxType IEquivalentType.EquivalentType { get; set; } - } + ; + 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; } + } } diff --git a/Dynamitey/DynamicObjects/Builder.cs b/Dynamitey/DynamicObjects/Builder.cs index 805ae8f..4253614 100644 --- a/Dynamitey/DynamicObjects/Builder.cs +++ b/Dynamitey/DynamicObjects/Builder.cs @@ -1,455 +1,446 @@ -// +// // 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 Dynamitey.Internal.Optimization; using System.Dynamic; using System.Reflection; -using Dynamitey.Internal.Optimization; 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(); + /// + /// 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) - { + + /// + /// 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 + { + private 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){ + /// + /// 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 + { + private 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) - { + /// + /// 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))) - { + 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; - } + } + } + + /// + /// 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); - } - } + /// + /// 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); + } + } } diff --git a/Dynamitey/DynamicObjects/Dictionary.cs b/Dynamitey/DynamicObjects/Dictionary.cs index c6c6b40..feaade8 100644 --- a/Dynamitey/DynamicObjects/Dictionary.cs +++ b/Dynamitey/DynamicObjects/Dictionary.cs @@ -1,12 +1,12 @@ - // +// // 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. @@ -14,130 +14,124 @@ // limitations under the License. using System.Collections; -using System.Dynamic; - - +using System.Dynamic; + 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(); + /// + /// 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() + { + } - foreach (var tKey in tKeys) - { - OnPropertyChanged(tKey); - } - } + /// + /// Initializes a new instance of the class. + /// + /// The dict. + public Dictionary(IEnumerable> dict) : base(dict) + { + } - /// - /// Gets or sets the with the specified key. - /// - /// - public object this[string key] - { - get => _dictionary[key]; - set => SetProperty(key, value); - } - } + /// + /// Gets the count. + /// + /// The count. + public int Count => _dictionary.Count; + + /// + /// Gets the enumerator. + /// + /// + public IEnumerator> GetEnumerator() + { + return _dictionary.GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } - /// - /// Adds extra synatx to intialize properties to match up with clay - /// - public class ChainableDictionary:Dictionary{ + /// + /// Clears this instance. + /// + public void Clear() + { + var tKeys = Keys; + + _dictionary.Clear(); + foreach (var tKey in tKeys) + { + OnPropertyChanged(tKey); + } + } - /// - /// Initializes a new instance of the class. - /// - public ChainableDictionary() - { - } + /// + /// Gets or sets the with the specified key. + /// + /// + public object this[string key] + { + get => _dictionary[key]; + set => SetProperty(key, value); + } + } - /// - /// Initializes a new instance of the class. - /// - /// The dict. - public ChainableDictionary(IEnumerable> dict) : base(dict) - { - } + /// + /// 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) + /// + /// 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)){ + if (base.TryInvokeMember(binder, args, out result)) + { return true; } - if(binder.CallInfo.ArgumentCount ==1){ - SetProperty(binder.Name, args.FirstOrDefault()); + 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; - } - + if (binder.CallInfo.ArgumentCount > 1) + { + SetProperty(binder.Name, new List(args)); + result = this; + return true; + } + return false; } } diff --git a/Dynamitey/DynamicObjects/Dummy.cs b/Dynamitey/DynamicObjects/Dummy.cs index bbef885..08f46a8 100644 --- a/Dynamitey/DynamicObjects/Dummy.cs +++ b/Dynamitey/DynamicObjects/Dummy.cs @@ -1,97 +1,85 @@ -using Dynamitey.Internal.Optimization; - - +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; - } + /// + /// 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 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) - { + /// + /// 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); + } - 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 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; - } - } + /// + /// 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; + } + } } diff --git a/Dynamitey/DynamicObjects/ExtensionToInstanceProxy.cs b/Dynamitey/DynamicObjects/ExtensionToInstanceProxy.cs index ef6b67d..e8d0a4a 100644 --- a/Dynamitey/DynamicObjects/ExtensionToInstanceProxy.cs +++ b/Dynamitey/DynamicObjects/ExtensionToInstanceProxy.cs @@ -1,433 +1,412 @@ -using System.Dynamic; -using System.Reflection; +using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; -using Dynamitey.Internal.Optimization; +using System.Dynamic; +using System.Reflection; 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); - - } - - - } + /// + /// 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); + } + } } diff --git a/Dynamitey/DynamicObjects/Factory.cs b/Dynamitey/DynamicObjects/Factory.cs index b080edb..a539460 100644 --- a/Dynamitey/DynamicObjects/Factory.cs +++ b/Dynamitey/DynamicObjects/Factory.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -15,115 +15,105 @@ namespace Dynamitey.DynamicObjects { - /// - /// Base Class for making a fluent factory using an Impromptu Interface return type. - /// - - - public class BaseFactory:BaseObject - { - + /// + /// Base Class for making a fluent factory using an Impromptu Interface return type. + /// - /// - /// 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; - } + 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; - } + /// + /// 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); + } - /// - /// 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; + } + } - /// - /// 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 + /// - /// - /// 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(); + protected readonly Dictionary _hashFactoryTypes = new Dictionary(); - /// - /// Lock for accessing singletons - /// - protected readonly object _lockTable = new object(); + /// + /// 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; + } + } - /// - /// 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]; - } - } - } + return _hashFactoryTypes[memberName]; + } + } + } } diff --git a/Dynamitey/DynamicObjects/FauxType.cs b/Dynamitey/DynamicObjects/FauxType.cs index c5e22a4..c053a42 100644 --- a/Dynamitey/DynamicObjects/FauxType.cs +++ b/Dynamitey/DynamicObjects/FauxType.cs @@ -2,271 +2,255 @@ 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(); - } - } + /// + /// 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(); + } + } } diff --git a/Dynamitey/DynamicObjects/FluentStringLookup.cs b/Dynamitey/DynamicObjects/FluentStringLookup.cs index 443d9fe..7119605 100644 --- a/Dynamitey/DynamicObjects/FluentStringLookup.cs +++ b/Dynamitey/DynamicObjects/FluentStringLookup.cs @@ -2,56 +2,51 @@ 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; - } - - - } + /// + /// 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; + } + } } diff --git a/Dynamitey/DynamicObjects/Get.cs b/Dynamitey/DynamicObjects/Get.cs index 5cb7f11..0605ed3 100644 --- a/Dynamitey/DynamicObjects/Get.cs +++ b/Dynamitey/DynamicObjects/Get.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -18,122 +18,113 @@ namespace Dynamitey.DynamicObjects { - /// - /// Dynamic Proxy that exposes any properties of objects, and can massage results based on interface - /// + /// + /// Dynamic Proxy that exposes any properties of objects, and can massage results based on interface + /// - - public class Get:BaseForwarder - { - + public class Get : BaseForwarder + { + /// + /// Initializes a new instance of the class. + /// + /// The target. + public Get(object target) : base(target) + { + } - /// - /// 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; + } + } - /// - /// 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; - } - } + 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; + } + } } diff --git a/Dynamitey/DynamicObjects/LateType.cs b/Dynamitey/DynamicObjects/LateType.cs index 30255cb..f0f9ad7 100644 --- a/Dynamitey/DynamicObjects/LateType.cs +++ b/Dynamitey/DynamicObjects/LateType.cs @@ -1,155 +1,142 @@ -using System.Dynamic; -using System.Reflection; -using Dynamitey.Internal.Optimization; - - +using Dynamitey.Internal.Optimization; +using System.Dynamic; +using System.Reflection; + 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); - } - } - - - - } + /// + /// 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); + } + } + } } diff --git a/Dynamitey/DynamicObjects/Lazy.cs b/Dynamitey/DynamicObjects/Lazy.cs index f60ec9a..e252eb8 100644 --- a/Dynamitey/DynamicObjects/Lazy.cs +++ b/Dynamitey/DynamicObjects/Lazy.cs @@ -1,87 +1,84 @@ namespace Dynamitey.DynamicObjects { + /// + /// Abstract base for the Generic class with fatory methods + /// - /// - /// 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); - } + 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); + } - /// - /// Initializes a new instance of the class. - /// - /// The target. - protected Lazy(object target) : base(target) - { - } + /// + /// 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) - { - } + /// + /// Wraps a Lazy Type evalutaes on first method call + /// + /// - /// - /// Initializes a new instance of the class. - /// - /// The value factory. - public Lazy(Func valueFactory ):base(new System.Lazy(valueFactory)) - { - - } - + public class Lazy : Lazy + { + /// + /// Initializes a new instance of the class. + /// + /// The target. + public Lazy(System.Lazy target) : base(target) + { + } - /// - /// 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(); - } + /// + /// Initializes a new instance of the class. + /// + /// The value factory. + public Lazy(Func valueFactory) : base(new System.Lazy(valueFactory)) + { + } - /// - /// Gets the call target. - /// - /// - /// The call target. - /// - protected override object CallTarget => ((System.Lazy) Target).Value; - } + /// + /// 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; + } } diff --git a/Dynamitey/DynamicObjects/LinqInstanceProxy.cs b/Dynamitey/DynamicObjects/LinqInstanceProxy.cs index f40b67d..8177d1d 100644 --- a/Dynamitey/DynamicObjects/LinqInstanceProxy.cs +++ b/Dynamitey/DynamicObjects/LinqInstanceProxy.cs @@ -1,197 +1,322 @@ -using System.Collections; - - +using System.Collections; + 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); - /// - /// 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 + IOrderedLinq ThenByDescending(Func keySelector, IComparer comparer); + } + // ReSharper restore UnusedMember.Global +#pragma warning restore 1591 } diff --git a/Dynamitey/DynamicObjects/List.cs b/Dynamitey/DynamicObjects/List.cs index 36bc767..c1cf98d 100644 --- a/Dynamitey/DynamicObjects/List.cs +++ b/Dynamitey/DynamicObjects/List.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -18,399 +18,379 @@ 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 - } + /// + /// 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; + } + + /// + /// 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; + + 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; + } } diff --git a/Dynamitey/DynamicObjects/Mimic.cs b/Dynamitey/DynamicObjects/Mimic.cs index e3ac449..284fc58 100644 --- a/Dynamitey/DynamicObjects/Mimic.cs +++ b/Dynamitey/DynamicObjects/Mimic.cs @@ -1,159 +1,156 @@ -using System.Dynamic; - - +using System.Dynamic; + 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) - { + /// + /// Class for TDD, used for mocking any dynamic object + /// - result = Dynamic.InvokeConstructor(binder.ReturnType); - return true; - } + 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 TryCreateInstance(CreateInstanceBinder binder, object[] args, 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 TryDeleteIndex(DeleteIndexBinder binder, object[] indexes) - { - 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 TryDeleteMember(DeleteMemberBinder binder) - { - return true; - } + /// + /// Override on DynamicObject + /// + /// + /// + /// + public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes) + { + 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 TryDeleteMember(DeleteMemberBinder binder) + { + 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 TryGetIndex(GetIndexBinder binder, object[] indexes, 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 TryGetMember(GetMemberBinder binder, 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 TryInvoke(InvokeBinder 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 TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + result = new Mimic(); + return true; + } - /// - /// Override on DynamicObject - /// - /// - /// - /// - public override bool TrySetMember(SetMemberBinder binder, object value) - { - return true; - } + /// + /// Override on DynamicObject + /// + /// + /// + /// + /// + public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) + { + return true; + } - /// - /// Override on DynamicObject - /// - /// - /// - /// - public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) - { - result = new Mimic(); - 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; + } + } } diff --git a/Dynamitey/DynamicObjects/Recorder.cs b/Dynamitey/DynamicObjects/Recorder.cs index c43c7c0..7cd505c 100644 --- a/Dynamitey/DynamicObjects/Recorder.cs +++ b/Dynamitey/DynamicObjects/Recorder.cs @@ -1,153 +1,149 @@ -// +// // 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 Dynamitey.Internal.Optimization; - - +// limitations under the License. + +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(); - } + /// + /// 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; } + /// + /// Gets or sets the recording. + /// + /// The recording. - /// - /// Initializes a new instance of the class. - /// - /// The target. - public Recorder(object target) : base(target) - { - Recording = new List(); - } + public IList Recording { get; protected set; } - /// - /// Replays the recording on target. - /// - /// The target. - public T ReplayOn(T target) - { - foreach (var tInvocation in Recording) - { - tInvocation.InvokeWithStoredArgs(target); - } + /// + /// Initializes a new instance of the class. + /// + /// The target. + public Recorder(object target) : base(target) + { + Recording = new List(); + } - return target; - } + /// + /// Replays the recording on target. + /// + /// The target. + public T ReplayOn(T target) + { + foreach (var tInvocation in Recording) + { + tInvocation.InvokeWithStoredArgs(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; - } + return target; + } - /// - /// 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; - } + /// + /// 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 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 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 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 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 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; - } + /// + /// 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; + } + } } diff --git a/Dynamitey/DynamicObjects/RegexMatch.cs b/Dynamitey/DynamicObjects/RegexMatch.cs index 3f09c3c..e1db419 100644 --- a/Dynamitey/DynamicObjects/RegexMatch.cs +++ b/Dynamitey/DynamicObjects/RegexMatch.cs @@ -1,138 +1,133 @@ using System.Dynamic; -using System.Text.RegularExpressions; using System.Reflection; +using System.Text.RegularExpressions; 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(); - } - } + /// + /// 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(); + } + } } diff --git a/Dynamitey/Expando.cs b/Dynamitey/Expando.cs index fb8a12a..efe1c99 100644 --- a/Dynamitey/Expando.cs +++ b/Dynamitey/Expando.cs @@ -1,41 +1,42 @@ -// +// // 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; +using System.Dynamic; namespace Dynamitey { - public class Expando : Builder - { - // ReSharper disable StaticFieldInGenericType - private static readonly dynamic _expandoBuilder = new Builder().Object; - // ReSharper restore StaticFieldInGenericType + 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() - { - } + /// + /// 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; - } + /// + /// Gets the new expandoObject builder. This method is short hand for Build>ExpandoObject>.NewObject() + /// + /// The new expandoObject. + public static dynamic New => _expandoBuilder; + } } diff --git a/Dynamitey/FluentRegex.cs b/Dynamitey/FluentRegex.cs index eaca0e1..ceddf92 100644 --- a/Dynamitey/FluentRegex.cs +++ b/Dynamitey/FluentRegex.cs @@ -2,70 +2,68 @@ namespace Dynamitey { - /// - /// Extension Methods for fluent Regex - /// - public static class FluentRegex - { + /// + /// 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(); + } - /// - /// 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); - /// - /// 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(); + } - 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; + } - /// - /// 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 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); - } - - } + /// + /// Fluents the matches. + /// + /// The regex. + /// The input string. + /// + public static IEnumerable FluentMatches(this Regex regex, string inputString) + { + return Matches(inputString, regex); + } + } } diff --git a/Dynamitey/Internal/Compat/Net40.cs b/Dynamitey/Internal/Compat/Net40.cs index 6984fd4..3eec82d 100644 --- a/Dynamitey/Internal/Compat/Net40.cs +++ b/Dynamitey/Internal/Compat/Net40.cs @@ -1,13 +1,9 @@ - - - - -namespace Dynamitey.Internal.Compat +namespace Dynamitey.Internal.Compat { using System.Globalization; public static class Net40 - { + { #if NET40 || PROFILE158 public static Type GetTypeInfo(this Type type) @@ -21,20 +17,15 @@ public static MethodInfo GetMethodInfo(this Delegate del) } public static CultureInfo GetDefaultThreadCurrentCulture() { - return Thread.CurrentThread.CurrentCulture; - + return Thread.CurrentThread.CurrentCulture; } -#else - public static CultureInfo GetDefaultThreadCurrentCulture() { - - return CultureInfo.DefaultThreadCurrentCulture; - - } - -#endif +#else + public static CultureInfo GetDefaultThreadCurrentCulture() + { + return CultureInfo.DefaultThreadCurrentCulture; + } - } - +#endif + } } - diff --git a/Dynamitey/Internal/Curry.cs b/Dynamitey/Internal/Curry.cs index 07dd11b..b523852 100644 --- a/Dynamitey/Internal/Curry.cs +++ b/Dynamitey/Internal/Curry.cs @@ -1,88 +1,83 @@ -// +// // 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 Dynamitey.Internal.Optimization; using System.Dynamic; using System.Linq.Expressions; -using Dynamitey.Internal.Optimization; 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; - } - + /// + /// 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 @@ -96,50 +91,45 @@ public Type GetCustomType() } #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; - } - } - - - - + /// + /// 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; + } + } } diff --git a/Dynamitey/Internal/InvokeSetters.cs b/Dynamitey/Internal/InvokeSetters.cs index 160c544..542df8d 100644 --- a/Dynamitey/Internal/InvokeSetters.cs +++ b/Dynamitey/Internal/InvokeSetters.cs @@ -1,97 +1,95 @@ -using System.Collections; -using System.Dynamic; -using Dynamitey.Internal.Optimization; +using Dynamitey.Internal.Optimization; using Microsoft.CSharp.RuntimeBinder; +using System.Collections; +using System.Dynamic; 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; + /// + /// Internal class implmenation for + /// + public class InvokeSetters : DynamicObject + { + internal InvokeSetters() + { + } - //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); + /// + /// 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; - }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]; + //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; - } - } + 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; + } + } } diff --git a/Dynamitey/Internal/Optimization/BareBonesList.cs b/Dynamitey/Internal/Optimization/BareBonesList.cs index c749630..36c72db 100644 --- a/Dynamitey/Internal/Optimization/BareBonesList.cs +++ b/Dynamitey/Internal/Optimization/BareBonesList.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -17,103 +17,97 @@ 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; - } - - } - - + 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; + } + } } diff --git a/Dynamitey/Internal/Optimization/BinderHash.cs b/Dynamitey/Internal/Optimization/BinderHash.cs index 60f264d..72cace9 100644 --- a/Dynamitey/Internal/Optimization/BinderHash.cs +++ b/Dynamitey/Internal/Optimization/BinderHash.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -15,158 +15,143 @@ 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; - - - } - } + 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; + } + } } diff --git a/Dynamitey/Internal/Optimization/InvokeHelper-Regular.cs b/Dynamitey/Internal/Optimization/InvokeHelper-Regular.cs index 531eba5..6e627d4 100644 --- a/Dynamitey/Internal/Optimization/InvokeHelper-Regular.cs +++ b/Dynamitey/Internal/Optimization/InvokeHelper-Regular.cs @@ -1,289 +1,263 @@ -using System.Dynamic; +using Dynamitey.DynamicObjects; +using Microsoft.CSharp.RuntimeBinder; +using System.Dynamic; using System.Reflection; using System.Runtime.CompilerServices; -using Dynamitey.DynamicObjects; -using Microsoft.CSharp.RuntimeBinder; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; 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 +{ + 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 @@ -293,60 +267,58 @@ internal static CallSite CreateCallSite( 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( + )); + + 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, @@ -357,503 +329,478 @@ internal static CallSite CreateCallSite( 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); - } - } + { + 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); + } + } } diff --git a/Dynamitey/Internal/Optimization/Util.cs b/Dynamitey/Internal/Optimization/Util.cs index 740941f..2b33407 100644 --- a/Dynamitey/Internal/Optimization/Util.cs +++ b/Dynamitey/Internal/Optimization/Util.cs @@ -1,207 +1,196 @@ -// +// // 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. - - +// limitations under the License. + +using Dynamitey.DynamicObjects; using System.Dynamic; using System.Reflection; -using System.Runtime.CompilerServices; -using Dynamitey.DynamicObjects; - - +using System.Runtime.CompilerServices; + 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; - } - } + /// + /// 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; + } + } } diff --git a/Dynamitey/Invocation.cs b/Dynamitey/Invocation.cs index 3a83f12..8ab6f2d 100644 --- a/Dynamitey/Invocation.cs +++ b/Dynamitey/Invocation.cs @@ -1,294 +1,316 @@ -// +// // 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. - - +// limitations under the License. + using Microsoft.CSharp.RuntimeBinder; namespace Dynamitey { - /// - /// Type of Invocation - /// + /// + /// 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, - 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, + /// + /// Invoke += + /// + AddAssign, - } + /// + /// Invoke -= + /// + SubtractAssign, + /// + /// Invoke Event Property Test + /// + IsEvent, - /// - /// Storable representation of an invocation without the target - /// - public class Invocation - { + /// + /// Invoke Directly + /// + Invoke, - /// - /// Defacto Binder Name for Explicit Convert Op - /// - public static readonly string ExplicitConvertBinderName = "(Explicit)"; + /// + /// Invoke Directly DiscardResult + /// + InvokeAction, - /// - /// Defacto Binder Name for Implicit Convert Op - /// - public static readonly string ImplicitConvertBinderName = "(Implicit)"; + /// + /// Invoke Directly Return Value + /// + InvokeUnknown, + } - /// - /// Defacto Binder Name for Indexer - /// - public static readonly string IndexBinderName = "Item"; + /// + /// 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 Constructor - /// - public static readonly string ConstructorBinderName = "new()"; + /// + /// Defacto Binder Name for Indexer + /// + public static readonly string IndexBinderName = "Item"; - /// - /// 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; } + /// + /// Defacto Binder Name for Constructor + /// + public static readonly string ConstructorBinderName = "new()"; - /// - /// 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); - } + /// + /// Gets or sets the kind. + /// + /// The kind. + public InvocationKind Kind { get; protected set; } - /// - /// 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; - } + /// + /// Gets or sets the name. + /// + /// The name. + public String_OR_InvokeMemberName Name { get; protected set; } - /// - /// 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)); - } + /// + /// Gets or sets the args. + /// + /// The args. + public object[] Args { get; protected set; } - /// - /// 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); - } + /// + /// 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); + } - /// - /// 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; - } - } + /// + /// 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; + } - /// - /// 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) - { + /// + /// 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)); + } - 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) - { + /// + /// 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); + } - 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); - } + /// + /// 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); - } - } + /// + /// Invokes the invocation on specified target. + /// + /// The target. + /// + public virtual object InvokeWithStoredArgs(object target) + { + return Invoke(target, Args); + } + } } diff --git a/Dynamitey/InvokeArg.cs b/Dynamitey/InvokeArg.cs index 2f87653..663f65b 100644 --- a/Dynamitey/InvokeArg.cs +++ b/Dynamitey/InvokeArg.cs @@ -1,12 +1,12 @@ -// +// // 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. @@ -15,75 +15,73 @@ 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); - } + /// + /// Use for Named arguments passed to InvokeMethods + /// - /// - /// Create Function can set to variable to make cleaner syntax; - /// - public static readonly Func Create = - Return.Arguments((n, v) => new InvokeArg(n, v)); + 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; - } + /// + /// 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 name. + /// + /// The name. + public string Name { get; private set; } - /// - /// Gets or sets the argument value. - /// - /// The value. - public object Value { 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){} + /// + /// 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); - } - - } + /// + /// 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); + } + } } diff --git a/Dynamitey/InvokeContext.cs b/Dynamitey/InvokeContext.cs index 1aaab15..89d5b88 100644 --- a/Dynamitey/InvokeContext.cs +++ b/Dynamitey/InvokeContext.cs @@ -1,123 +1,117 @@ -// +// // 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. - - +// limitations under the License. + 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; - } - } + /// + /// 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; + } + } } diff --git a/Dynamitey/InvokeMemberName.cs b/Dynamitey/InvokeMemberName.cs index e751554..cc0fa2c 100644 --- a/Dynamitey/InvokeMemberName.cs +++ b/Dynamitey/InvokeMemberName.cs @@ -1,150 +1,145 @@ 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); + } - /// - /// 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 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; } + } - /// - /// 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)); - /// - /// 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)); - /// - /// 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); + } - /// - /// 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. - /// 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; + } - /// - /// 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); + } - /// - /// 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) - { + 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 + } - var tGenArgs = GenericArgs; - var tOtherGenArgs = other.GenericArgs; + /// + /// 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); + } - - 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()); - } - } - } + /// + /// 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()); + } + } + } } diff --git a/Dynamitey/PartialApply.cs b/Dynamitey/PartialApply.cs index 284eea1..85dfeb7 100644 --- a/Dynamitey/PartialApply.cs +++ b/Dynamitey/PartialApply.cs @@ -1,188 +1,180 @@ -using System.Dynamic; +using Dynamitey.Internal.Optimization; +using System.Dynamic; using System.Linq.Expressions; -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(); + /// + /// 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 - { - } + /// + /// 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 + { + } } diff --git a/Dynamitey/Tupler.cs b/Dynamitey/Tupler.cs index 5c87a3c..2add477 100644 --- a/Dynamitey/Tupler.cs +++ b/Dynamitey/Tupler.cs @@ -1,219 +1,213 @@ -// +// // 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 Dynamitey.Internal.Optimization; using System.Collections; using System.Reflection; -using Dynamitey.Internal.Optimization; 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; - } - } + /// + /// 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; + } + } } diff --git a/SupportLibrary/SupportTypes.cs b/SupportLibrary/SupportTypes.cs index 28e43d5..dc7fa50 100644 --- a/SupportLibrary/SupportTypes.cs +++ b/SupportLibrary/SupportTypes.cs @@ -3,492 +3,474 @@ 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(); - } - + 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 + { + private 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(); + } } diff --git a/Tests/Curry.cs b/Tests/Curry.cs index a8a9588..eac96b0 100644 --- a/Tests/Curry.cs +++ b/Tests/Curry.cs @@ -1,8 +1,5 @@ -using System; -using System.Linq; +using Dynamitey.SupportLibrary; using System.Text; -using Dynamitey.SupportLibrary; -using NUnit.Framework; namespace Dynamitey.Tests { diff --git a/Tests/DynamicObjects.cs b/Tests/DynamicObjects.cs index 755aec7..5009295 100644 --- a/Tests/DynamicObjects.cs +++ b/Tests/DynamicObjects.cs @@ -1,13 +1,7 @@ -using System; +using Dynamitey.SupportLibrary; using System.Collections; -using System.Collections.Generic; using System.Dynamic; -using System.Linq; using System.Runtime.CompilerServices; -using NUnit.Framework; -using Dynamitey; -using Dynamitey.DynamicObjects; -using Dynamitey.SupportLibrary; namespace Dynamitey.Tests { diff --git a/Tests/ExpandoObjs.cs b/Tests/ExpandoObjs.cs index f264892..b1f6626 100644 --- a/Tests/ExpandoObjs.cs +++ b/Tests/ExpandoObjs.cs @@ -1,5 +1,4 @@ using System.Dynamic; -using NUnit.Framework; namespace Dynamitey.Tests { diff --git a/Tests/Impromptu.cs b/Tests/Impromptu.cs index d0027a4..8a77753 100644 --- a/Tests/Impromptu.cs +++ b/Tests/Impromptu.cs @@ -88,7 +88,8 @@ public void DictionaryCurriedAcctlikeNullMethodsTest() public interface IBuilder { - INest Nester(object props); + INest Nester(object props); + INested Nester2(object props); [ImpromptuInterface.UseNamedArgument] diff --git a/Tests/Invoke.cs b/Tests/Invoke.cs index 38f45c0..82b31ec 100644 --- a/Tests/Invoke.cs +++ b/Tests/Invoke.cs @@ -1,14 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq.Expressions; -using System.Xml.Linq; -using Dynamitey.SupportLibrary; +using Dynamitey.SupportLibrary; using Microsoft.CSharp.RuntimeBinder; using Moq; -using NUnit.Framework; -using System.Globalization; using System.Drawing; +using System.Dynamic; +using System.Globalization; +using System.Linq.Expressions; +using System.Xml.Linq; namespace Dynamitey.Tests { @@ -1009,7 +1006,8 @@ private DynamicObject CreateMock(ExpressionType op) public class OperatorTestDynObject : DynamicObject { - ExpressionType _type; + private ExpressionType _type; + public OperatorTestDynObject(ExpressionType type) { _type = type; diff --git a/Tests/Linq.cs b/Tests/Linq.cs index 1864a85..cf0d73c 100644 --- a/Tests/Linq.cs +++ b/Tests/Linq.cs @@ -1,218 +1,208 @@ -using System.Collections; +using Python.Runtime; +using System.Collections; using System.Reflection; -using Python.Runtime; namespace Dynamitey.Tests { - [TestFixture] - public class Linq - { - - - [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.That(expected, Is.EqualTo(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.That(expected, Is.EqualTo(actual)); - - } - - private dynamic RunPythonHelper(object linq, string code) - { - using (Py.GIL()) - { - // Initialize a new Python dictionary to serve as the scope - using (PyDict pyGlobals = new PyDict()) - { - // Add the 'linq' variable to the Python scope - pyGlobals.SetItem("linq", linq.ToPython()); - - // Execute the provided code within the Python scope - PythonEngine.Exec(code.Trim(), pyGlobals); - - // Retrieve and return the 'result' variable from the Python scope - return pyGlobals.GetItem("result"); - } - } - } + [TestFixture] + public class Linq + { + [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.That(expected, Is.EqualTo(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.That(expected, Is.EqualTo(actual)); + } + + private dynamic RunPythonHelper(object linq, string code) + { + using (Py.GIL()) + { + // Initialize a new Python dictionary to serve as the scope + using (PyDict pyGlobals = new PyDict()) + { + // Add the 'linq' variable to the Python scope + pyGlobals.SetItem("linq", linq.ToPython()); + + // Execute the provided code within the Python scope + PythonEngine.Exec(code.Trim(), pyGlobals); + + // Retrieve and return the 'result' variable from the Python scope + return pyGlobals.GetItem("result"); + } + } + } // Need to revisit these tests. Commenting out for now. -// [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.That(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.That(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 - && HelperSingleGenericArgMatch(it.GetParameters().First().ParameterType.GetGenericArguments().Single()); - } - - bool HelperSingleGenericArgMatch(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 (HelperSingleGenericArgMatch(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 => !HelperSingleGenericArgMatch(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())); - } - } + // [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.That(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.That(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 + && HelperSingleGenericArgMatch(it.GetParameters().First().ParameterType.GetGenericArguments().Single()); + } + + private bool HelperSingleGenericArgMatch(Type info) + { + foreach (var name in new[] { "TSource", "TFirst", "TOuter" }) + { + if (info.Name == name) + { + return true; + } + } + + return false; + } + + // Define other methods and classes here + private string HelperFormatType(Type it) + { + if (HelperSingleGenericArgMatch(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; + } + } + + private string HelperGenericParams(Type[] it) + { + var tArgs = it.Where(t => !HelperSingleGenericArgMatch(t)).Select(t => HelperFormatType(t)); + if (!tArgs.Any()) + { + return ""; + } + return "<" + String.Join(",", tArgs) + ">"; + } + + private 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); + } + + private string HelperGetParams(ParameterInfo[] it) + { + var parms = it.Skip(1); + return String.Join(",", parms.Select(p => HelperFormatType(p.ParameterType) + " " + p.Name)); + } + + private string HelperGetParamsDebug(ParameterInfo[] it) + { + var parms = it; + return String.Join(",", parms.Select(p => HelperFormatType(p.ParameterType) + " " + p.Name)); + } + + private string HelperMakeName(MethodInfo it) + { + return String.Format("{0} {1}{2}({3});", HelperReturnTypeSub(it.ReturnType), it.Name, HelperGenericParams(it.GetGenericArguments()), HelperGetParams(it.GetParameters())); + } + + private string HelperMakeNameDebug(MethodInfo it) + { + return String.Format("{0} {1}{2}({3});", HelperReturnTypeSub(it.ReturnType), it.Name, HelperGenericParams(it.GetGenericArguments()), HelperGetParamsDebug(it.GetParameters())); + } + } } diff --git a/Tests/MimicTest.cs b/Tests/MimicTest.cs index 42cfc44..ddc8059 100644 --- a/Tests/MimicTest.cs +++ b/Tests/MimicTest.cs @@ -1,172 +1,172 @@ 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.That(4, Is.EqualTo(result)); - } - - [Test] - public void Inheritance_String() - { - dynamic mimic = new SubMimic(); - string result = mimic.Add("He", "llo"); - Assert.That("Hello", Is.EqualTo(result)); - } - - [Test] - public void Inheritance_No_Match() - { - dynamic mimic = new SubMimic(); - int result = mimic.Add(1, "llo"); - Assert.That(default(int), Is.EqualTo(result)); - } - } + /// + /// 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.That(4, Is.EqualTo(result)); + } + + [Test] + public void Inheritance_String() + { + dynamic mimic = new SubMimic(); + string result = mimic.Add("He", "llo"); + Assert.That("Hello", Is.EqualTo(result)); + } + + [Test] + public void Inheritance_No_Match() + { + dynamic mimic = new SubMimic(); + int result = mimic.Add(1, "llo"); + Assert.That(default(int), Is.EqualTo(result)); + } + } } diff --git a/Tests/PrivateTest.cs b/Tests/PrivateTest.cs index 47c4075..d41019a 100644 --- a/Tests/PrivateTest.cs +++ b/Tests/PrivateTest.cs @@ -3,69 +3,68 @@ namespace Dynamitey.Tests { - [TestFixture] - public class PrivateTest - { - - [Test] - public void TestInvokePrivateMethod() - { - var tTest = new TestWithPrivateMethod(); - Assert.That((object)Dynamic.InvokeMember(tTest, "Test"), Is.EqualTo(3)); - } + [TestFixture] + public class PrivateTest + { + [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 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 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 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 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 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)); - } - } + [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; - } - } + public class TestWithPrivateMethod + { + private int Test() + { + return 3; + } + } } diff --git a/Tests/SpeedTest.cs b/Tests/SpeedTest.cs index 618a28b..976c752 100644 --- a/Tests/SpeedTest.cs +++ b/Tests/SpeedTest.cs @@ -3,782 +3,719 @@ namespace Dynamitey.Tests { - [TestFixture] - [Category("Performance")] - public class SpeedTest - { - [OneTimeSetUp] - public void WarmUpDlr() - { - Dynamic.InvokeMember(1, "ToString"); - } - - - public TimeIt Timer; - [SetUp] - public void Setup() - { - Timer = new TimeIt(); - } - - - [Test] - public void PropPocoGetValueTimed() - { + [TestFixture] + [Category("Performance")] + public class SpeedTest + { + [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"); + 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() - { + 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"); + 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() - { - + 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() - { + 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"); + 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() - { + 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"); + 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() - { + 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"); + 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() - { + 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"); + 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() - { - + 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"); + 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() - { - + 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"); + 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() - { - + 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"); + 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() - { + 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"); + 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); - - } - } + 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); + } + } } diff --git a/Tests/TimeIt.cs b/Tests/TimeIt.cs index 4c3512b..54ae843 100644 --- a/Tests/TimeIt.cs +++ b/Tests/TimeIt.cs @@ -2,83 +2,84 @@ namespace Dynamitey.Tests { - public class TimeIt - { - public const int Million = 1000000; + 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++; - } + private Stopwatch _watch1; + private Stopwatch _watch2; + private Stopwatch _watch3; + private bool _skipInitializationCosts; - for (int i = 0; i < iteration; i++) - { - _watch1.Start(); - Action1(); - _watch1.Stop(); - _watch2.Start(); - Action2(); - _watch2.Stop(); - if (useThree) - { - _watch3.Start(); - Action3(); - _watch3.Stop(); - } + public TimeIt(bool skipInitializationCosts = false) + { + _watch1 = new Stopwatch(); + _watch2 = new Stopwatch(); + _watch3 = new Stopwatch(); + _skipInitializationCosts = skipInitializationCosts; + } - if (i == 0 && _skipInitializationCosts) - { - _watch1.Reset(); - _watch2.Reset(); - _watch3.Reset(); - } - } + public Tuple GoThree(int iteration = Million, bool useThree = true) + { + if (_skipInitializationCosts) + { + iteration++; + } - return Tuple.Create(_watch1.Elapsed, _watch2.Elapsed, _watch3.Elapsed); + for (int i = 0; i < iteration; i++) + { + _watch1.Start(); + Action1(); + _watch1.Stop(); + _watch2.Start(); + Action2(); + _watch2.Stop(); + if (useThree) + { + _watch3.Start(); + Action3(); + _watch3.Stop(); + } - } - public Tuple Go(int iteration = Million) - { - var goThree = GoThree(iteration, false); - return Tuple.Create(goThree.Item1, goThree.Item2); - } + if (i == 0 && _skipInitializationCosts) + { + _watch1.Reset(); + _watch2.Reset(); + _watch3.Reset(); + } + } - public Action Action1 { get; set; } - public Action Action2 { get; set; } - public Action Action3 { get; set; } + return Tuple.Create(_watch1.Elapsed, _watch2.Elapsed, _watch3.Elapsed); + } - 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"); - } + 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; } - 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"); - } - } + 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"); + } + } } diff --git a/Tests/TuplerTest.cs b/Tests/TuplerTest.cs index 011b77a..dcbbe54 100644 --- a/Tests/TuplerTest.cs +++ b/Tests/TuplerTest.cs @@ -1,149 +1,143 @@ 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)); - } - } + [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)); + } + } }