How to combine Expression<TDelegate> objects without invoking? - c#

I have a delegate as follows:
public delegate TestResult TestCase(byte[] source);
...where the return TestResult is as follows:
public class TestResult {
public bool Pass { get; }
public int Index { get; }
public TestResult(bool result, int index) {
Pass = result;
Index = index;
}
}
An example TestCase delegate looks like:
public static TestResult In(byte[] tkn, ITestSet testSet) {
return testSet.Contains(tkn);
}
ITestSet is not much more than an encapsulated HashSet<byte[]>.
In one use case I have 2 test sets: (1) A - z, (2) 0 - 9. I want to test if an input byte[] is in either test set.
I am using Expression<TestCase> but having trouble figuring out how to implement the Or test case. I have a TestCaseBuilder with the following methods:
public class TestCaseBuilder {
private Expression<TestCase> tcExpr;
public TestCaseBuilder With(TestCaseBuilder tcBuilder) {
tcExpr = tcBuilder.tcExpr;
return this;
}
public TestCaseBuilder Or(TestCaseBuilder tcBuilder) {
tcExpr = tcExpr.Or(tcBuilder.tcExpr);
return this;
}
}
...and my extension method:
public static Expression<TestCase> Or (this Expression<TestCase> tcLeft, Expression<TestCase> tcRight) {
var lExpr = (LambdaExpression)tcLeft;
var rExpr = (LambdaExpression)tcRight;
var param = lExpr.Parameters;
return Expression.Lambda<TestCase>(/* what to do here ? */, param);
}
Expression.OrElse is mechanically what I would think is appropriate but cannot use that since I am returning a TestResult, not a bool.
Here is how the TestCaseBuilder is used:
testcaseBuilder.As("Foo")
.With(isLetterTestCase)
.Or(isDigitTestCase);
I have performed the Or using just the TestCase delegates:
public static TestCase Or(this TestCase tc1, TestCase tc2) {
return tkn => {
var res = tc1(tkn);
if (res.Pass) {
return res;
}
return tc2(tkn);
};
}
How can I combine the 2 Expression<TestCase> in a custom Or method without invoking the first test case?

Is this what you wanted
public static Expression<Func<byte[], TestResult, TestCase, TestResult>> helperExp = (inp, res, next) => res.Pass ? next(inp) : res;
public static Expression<TestCase> Or(Expression<TestCase> exp1, Expression<TestCase> exp2)
{
var param = exp1.Parameters;
Expression<TestCase> or = Expression.Lambda<TestCase>(
Expression.Invoke(helperExp,
param[0], Expression.Invoke(exp1, param), exp2),param);
return or;
}
With a block expression no invoke
public static Expression<TestCase> Or(Expression<TestCase> exp1, Expression<TestCase> exp2)
{
var param = exp1.Parameters;
ParameterExpression local = Expression.Parameter(typeof(TestResult), "local");
BlockExpression block = Expression.Block(
new[] { local },
Expression.Assign(local, exp1.Body),
Expression.Condition(Expression.Property(local, nameof(TestResult.Pass)), exp2.Body, local));
return Expression.Lambda<TestCase>(block, param);
}
Test
Expression<TestCase> exp1 = (tc) => new TestResult(true);
Expression<TestCase> exp2 = (tc) => new TestResult(false);
var first = Or(exp1, exp1);
var second = Or(first, exp2);
var func = second.Compile();
var result = func(new byte[] { });
There might be a better way to do a conditional monad without expressions using https://github.com/louthy/csharp-monad
I thing .net core uses the monad principle for middleware.

Related

C# Type T return with Func<T> delegate as argument

I have this mapping function to convert types when migrating services to keep the return types compatible -
private T JsonMap<T>(object obj)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
}
but what I find myself doing a lot is -
public async Task<T1> DoWork(T2 obj)
{
var requestMapped = JsonMap<T3>(obj);
var response = await _myService.DoWork(requestMapped);
var responseMapped = JsonMap<T1>(response);
return responseMapped;
}
As a result, I was trying to think of a way to incorporate that into the JsonMap function, but having difficulties there. Trying to have something like -
public async T1 JsonMap<T1>(object obj, Func<T3,T4> myFunc)
{
var requestMapped = JsonMap<T3>(obj);
var response = await myFunc(requestMapped);
var responseMapped = JsonMap<T1>(response);
return responseMapped;
}
and use it like this -
public async Task<T1> DoWork(T2 obj)
{
return await JsonMap<T1>(obj, _myService.DoWork);
}
but I'm not too sure how that would work in terms of delegates. If someone could help point me in the right direction that would be helpful.
You could use declared delegates and pass them to your generic process.
I have updated the example to make it async, at the end of the day you should be able to call
Converter c = new Converter();
TestType2 tt2 = new TestType2() { testValue = "Something to test" };
TestType1 tt1 = await c.JsonMap<TestType1, TestType2>(tt2);
I have put an example as RexTester
using Newtonsoft.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace ConsoleApp1
{
public class TestType1
{
public string testValue { get; set; }
}
public class TestType2
{
public string testValue { get; set; }
}
public class TestType3
{
public string testValue { get; set; }
}
public class Conversion
{
public System.Type ConverionType { get; set; }
public object ConversionFunction { get; set; }
}
public class Converter
{
public delegate Task<T> processingFuncDel<T, T1>(T1 value);
Dictionary<System.Type, Conversion> conversionDelegates = new Dictionary<System.Type, Conversion>();
public Converter()
{
processingFuncDel<TestType2, TestType3> convert3To2 = new processingFuncDel<TestType2, TestType3>(myFunc);
Conversion c = new Conversion() { ConverionType = typeof(TestType3), ConversionFunction = convert3To2 };
conversionDelegates.Add(typeof(TestType3), c);
// Add more converters here
}
public async Task<T1> JsonMap<T1, T2>(T2 obj)
{
if (conversionDelegates.ContainsKey(obj.GetType()))
{
System.Type ct = conversionDelegates[obj.GetType()].ConverionType;
if(ct == typeof(TestType3))
{
return await JsonMap<T1, T2, TestType3>(obj, (processingFuncDel<T2, TestType3>)conversionDelegates[obj.GetType()].ConversionFunction);
}
// Add more cases here, or use reflection to try an do it dynamically...
}
return default(T1);
}
public async Task<T1> JsonMap<T1, T2, T3>(T2 obj, processingFuncDel<T2, T3> myFunc)
{
T3 requestMapped = JsonMap<T3>(obj);
T2 response = await myFunc(requestMapped);
T1 responseMapped = JsonMap<T1>(response);
return responseMapped;
}
public T JsonMap<T>(object obj)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
}
public async Task<TestType2> myFunc(TestType3 obj)
{
// Do your async processing here, this is just an example
TestType2 ret = new TestType2() { testValue = obj.testValue };
return ret;
}
}
public class Program
{
public static void Main(string[] args)
{
Converter c = new Converter();
TestType2 tt2 = new TestType2() { testValue = "Something to test" };
// Make an async call to convert
TestType1 tt1 = c.JsonMap<TestType1, TestType2>(tt2).GetAwaiter().GetResult();
}
}
}
Asynchronous delegates are just like regular delegates, except the return type is wrapped in Task<>. So in your case, you'd want something like Func<T1, Task<T2>>:
public async Task<T1> JsonMap<T1, T3, T4>(object obj, Func<T3, Task<T4>> myFunc)
{
var requestMapped = JsonMap<T3>(obj);
var response = await myFunc(requestMapped);
var responseMapped = JsonMap<T1>(response);
return responseMapped;
}
The problem with very-generic methods like this is that the consumer has to specify all the type parameters explicitly. C# doesn't allow you to specify only the first parameter and infer the other two:
_ = await JsonMap<T1, T3, T4>(obj, _myService.DoWork);
You can work around this with a few type tricks, e.g.:
public static class JsonMapper<T1>
{
public static async Task<T1> Map<T3, T4>(object obj, Func<T3, Task<T4>> myFunc)
{
var requestMapped = JsonMap<T3>(obj);
var response = await myFunc(requestMapped);
var responseMapped = JsonMap<T1>(response);
return responseMapped;
}
}
which can be used as:
_ = await JsonMapper<T1>.Map(obj, _myService.DoWork);
Alternatively, you can drop the final mapping from your implementation:
public async Task<T4> JsonMap<T3, T4>(object obj, Func<T3, Task<T4>> myFunc)
{
var requestMapped = JsonMap<T3>(obj);
var response = await myFunc(requestMapped);
return response;
}
which can be used as:
_ = await JsonMap<T1>(JsonMap(obj, _myService.DoWork));
Doesn't answer your question exactly, but you might be able to reach your goal of simpler code simply by changing JsonMap to an extension method.
static public T JsonMap<T>(this object obj)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
}
Now DoWork is one line:
public Task<T1> DoWork(T2 obj)
{
return _myService.DoWork(obj.JsonMap<T3>()).JsonMap<T1>;
}

Lambda expression as inline data in xUnit

I'm pretty new to xUnit and here's what I'd like to achieve:
[Theory]
[InlineData((Config y) => y.Param1)]
[InlineData((Config y) => y.Param2)]
public void HasConfiguration(Func<Config, string> item)
{
var configuration = serviceProvider.GetService<GenericConfig>();
var x = item(configuration.Config1); // Config1 is of type Config
Assert.True(!string.IsNullOrEmpty(x));
}
Basically, I have a GenericConfig object which contains Config and other kind of configurations, but I need to check that every single parameter is valid. Since they're all string, I wanted to simplify using [InlineData] attribute instead of writing N equals tests.
Unfortunately the error I'm getting is "Cannot convert lambda expression to type 'object[]' because it's not a delegate type", which is pretty much clear.
Do you have any idea on how to overcome this?
In addition to the already posted answers. The test cases can be simplified by directly yielding the lambdas.
public class ConfigTestDataProvider
{
public static IEnumerable<object[]> TestCases
{
get
{
yield return new object [] { (Func<Config, object>)((x) => x.Param1) };
yield return new object [] { (Func<Config, object>)((x) => x.Param2) };
}
}
}
This test ConfigTestDataProvider can then directly inject the lambdas.
[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(Func<Config, object> func)
{
var config = serviceProvider.GetService<GenericConfig>();
var result = func(config.Config1);
Assert.True(!string.IsNullOrEmpty(result));
}
Actually, I was able to find a solution which is a bit better than the one provided by Iqon (thank you!).
Apparently, the InlineData attribute only supports primitive data types. If you need more complex types, you can use the MemberData attribute to feed the unit test with data from a custom data provider.
Here's how I solved the problem:
public class ConfigTestCase
{
public static readonly IReadOnlyDictionary<string, Func<Config, string>> testCases = new Dictionary<string, Func<Config, string>>
{
{ nameof(Config.Param1), (Config x) => x.Param1 },
{ nameof(Config.Param2), (Config x) => x.Param2 }
}
.ToImmutableDictionary();
public static IEnumerable<object[]> TestCases
{
get
{
var items = new List<object[]>();
foreach (var item in testCases)
items.Add(new object[] { item.Key });
return items;
}
}
}
And here's the test method:
[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(string currentField)
{
var func = ConfigTestCase.testCases.FirstOrDefault(x => x.Key == currentField).Value;
var config = serviceProvider.GetService<GenericConfig>();
var result = func(config.Config1);
Assert.True(!string.IsNullOrEmpty(result));
}
I could maybe come up with something a bit better or cleaner, but for now it works and the code is not duplicated.
I have the problem the same to you, and I found the solution that using TheoryData class and MemberData attribute. Here is the example and I hope the code usefully:
public class FooServiceTest
{
private IFooService _fooService;
private Mock<IFooRepository> _fooRepository;
//dummy data expression
//first parameter is expression
//second parameter is expected
public static TheoryData<Expression<Func<Foo, bool>>, object> dataExpression = new TheoryData<Expression<Func<Foo, bool>>, object>()
{
{ (p) => p.FooName == "Helios", "Helios" },
{ (p) => p.FooDescription == "Helios" && p.FooId == 1, "Helios" },
{ (p) => p.FooId == 2, "Poseidon" },
};
//dummy data source
public static List<Foo> DataTest = new List<Foo>
{
new Foo() { FooId = 1, FooName = "Helios", FooDescription = "Helios Description" },
new Foo() { FooId = 2, FooName = "Poseidon", FooDescription = "Poseidon Description" },
};
//constructor
public FooServiceTest()
{
this._fooRepository = new Mock<IFooRepository>();
this._fooService = new FooService(this._fooRepository.Object);
}
[Theory]
[MemberData(nameof(dataExpression))]
public void Find_Test(Expression<Func<Foo, bool>> expression, object expected)
{
this._fooRepository.Setup(setup => setup.FindAsync(It.IsAny<Expression<Func<Foo, bool>>>()))
.ReturnsAsync(DataTest.Where(expression.Compile()));
var actual = this._fooService.FindAsync(expression).Result;
Assert.Equal(expected, actual.FooName);
}
}
Oddly delegates are not objects, but Actions or Funcs are. To do this, you have to cast the lambda to one of these types.
object o = (Func<Config, string>)((Config y) => y.Param1)
But doing this, your expression is not constant anymore. So this will prevent usage in an Attribute.
There is no way of passing lambdas as attributes.
One possible solution would be to use function calls, instead of attributes. Not as pretty, but could solve your problem without duplicate code:
private void HasConfiguration(Func<Config, string> item)
{
var configuration = serviceProvider.GetService<GenericConfig>();
var x = item(configuration.Config1); // Config1 is of type Config
Assert.True(!string.IsNullOrEmpty(x));
}
[Theory]
public Test1()
{
HasConfiguration((Config y) => y.Param1);
}
[Theory]
public Test2()
{
HasConfiguration((Config y) => y.Param2);
}
public class HrcpDbTests
{
[Theory]
[MemberData(nameof(TestData))]
public void Test(Expression<Func<bool>> exp)
{
// Arrange
// Act
// Assert
}
public static IEnumerable<object[]> TestData
{
get
{
Expression<Func<bool>> mockExp1 = () => 1 == 0;
Expression<Func<bool>> mockExp2 = () => 1 != 2;
return new List<object[]>
{
new object[]
{
mockExp1
},
new object[]
{
mockExp2
}
}
}
}
}

How can I call a reflected Func<T, T> property using Expression Trees

I have a generic class with a lambda property defined as such:
public class Transformation<TProperty> : TransformationBase
{
public Func<TProperty, TProperty> Transform { get; private set; }
...
I'm trying to compile an Action that can call this Transform property (on a property of Foo). I don't know TProperty at compile-time. I've started with this:
private static Action<Foo> Compile(Transformation transformation)
{
var fooParameter = Expression.Parameter(typeof(Foo));
var changePropertyValue = Expression.Constant(transformation);
var transformProperty = Expression.Property(changePropertyValue, "Transform");
var transfromCall = Expression.Call(transformProperty, ?
}
How can I call/execute the transformProperty?
EDIT: Foo (which is known a compile time) has an untyped property Value which needs to be transformed using the Transform property of the Transformation:
public class Foo {
public object Value { get; set; }
}
So, hand-written as an example where TProperty is string it would be:
Foo foo = ... // coming from an external source
Transformation<string> tranformation = ... // coming from an external source
foo.Value = transformation.Transform((string)foo.Value);
Except that I don't know the exact type of the Transformation as it is defined in an external assembly. So, instead of string it could be int or something else. That's why I want to use Expression Trees to compile an Action for a given transformation, such that I can call:
Foo foo = ... // coming from an external source
TransformationBase transformation = ... // coming from an external source
Action<Foo> transform = Compile(transformation);
transform(foo); // should transform foo.Value using the Transform property of 'transformation'
Note: I made Transformation inherit from TransformationBase to clarify this discussion.
Your problems relate more to the lack of typing around your problem. Foo.Value is loosely typed, but your transform functions are strongly typed. Expression Trees are also strongly typed. Using them doesn't allow you to magically call code in a loosely typed manner.
The solution is either a lot of reflection, or some easy dynamic:
EDIT: I added CompileUntyped which uses ExpressionTrees.I also added CompileReflection, which uses Reflection without ExpressionTrees. I would recommend the one that uses dynamic. It is by far the easiest to read, hence the easiest to maintain.
class Program
{
static void Main(string[] args)
{
var testTransform = new Transformation<string>
{
Transform = s => s.ToUpper()
};
var a = Compile(testTransform);
var foo = new Foo
{
Value = "test"
};
a(foo);
//foo.Value is now TEST
}
public static Action<Foo> CompileReflection(TransformationBase transformation)
{
var f = transformation
.GetType()
.GetProperty("Transform")
.GetGetMethod()
.Invoke(transformation, null) as Delegate;
return foo => foo.Value = f.DynamicInvoke(foo.Value);
}
public static Action<Foo> Compile(TransformationBase transformation)
{
return new Action<Foo>(f =>
{
dynamic d = f.Value;
dynamic t = transformation;
f.Value = t.Transform(d);
});
}
public static Action<Foo> CompileUntyped(TransformationBase transformation)
{
var transformType = transformation.GetType();
var genericType = transformType.GetGenericArguments().First();
var fooParam = Expression.Parameter(typeof(Foo), "f");
var valueGetter = typeof(Foo).GetProperty("Value").GetGetMethod();
var valueSetter = typeof(Foo).GetProperty("Value").GetSetMethod();
var transformFuncMember = transformType.GetProperty("Transform").GetGetMethod();
//Equivalent to f => f.Value = transformation.Transform((T)f.Value)
//Where T is the generic type parameter of the Transformation, and f is of type Foo
var expression = Expression.Lambda<Action<Foo>>(
Expression.Call(
fooParam,
valueSetter,
Expression.Invoke(
Expression.Property(
Expression.Constant(transformation, transformType),
transformFuncMember
),
Expression.Convert(
Expression.Property(fooParam, valueGetter),
genericType
)
)
), fooParam
);
return expression.Compile();
}
}
public class TransformationBase { }
public class Transformation<TProperty> : TransformationBase
{
public Func<TProperty, TProperty> Transform { get; set; }
}
public class Foo
{
public object Value { get; set; }
}
Not sure what are you trying to do BUT if I understand your intentions - I do not see need for compiling Expressions:
private static Action<TProperty> Compile<TProperty>(Transformation<TProperty> transformation)
{
return new Action<TProperty>(p => transformation.Transform(p));
}
See an example, it should give you what you want.
void Main()
{
var dummyObject = new Dummy { Test = "Hello!" };
var propertyTransform = Create(dummyObject, "Test");
propertyTransform(dummyObject);
Console.WriteLine("Final transformation " + dummyObject.Test);
}
class Dummy {
public string Test { get; set; }
}
// Define other methods and classes here
public class Transformation<TProperty>
{
public Func<TProperty, TProperty> Transform { get; set; }
}
public static Action<TObj> Create<TObj>(TObj myObject, string property){
var prop = myObject
.GetType()
.GetProperty(property);
var val = prop.GetValue(myObject);
var transformation = Create((dynamic)val);
var transform = transformation.Transform;
return obj => {
var newValue = transform((dynamic)val);
prop.SetValue(myObject, newValue);
};
}
public static Transformation<TProperty> Create<TProperty>(TProperty property){
var transformation = new Transformation<TProperty>();
// just a dummy hijacking.
if(typeof(TProperty)==typeof(string)){
Func<string, string> test = input => "I am changed man!";
transformation.Transform = (dynamic)test;
}
return transformation;
}
Output:
Final transformation I am changed man!

Create Expression for new Action<T> where T is unknown at compile time

Edit2: removed a load of gubbins + bounty.
I have deconstructed an expression for a message bus in the hope of reconstructing it and invoking it in a slightly different manner. The serialization and deserialization is successful and I am able to create instances of most of what I need.
//Deconstruct
Expression<Func<T, Task>> expression
proxy => proxy.serviceMethod(arg);
I need to create the syntax below. T is an interface to a WCF service. This expression will be passed to a service invoker where it's internal ChannelFactory will pass it into this method.
//Reconstruct this as expression so I can pass it as a parameter
var myAction = new Action<T>(proxy => {
proxy.serviceMethod((SomeType)SomeParameter));
});
// to pass to this method
serviceInvokerTMethod.Invoke(serviceInvokerTInstance, new object[] { myAction });
What I have:
//I think i'm nearly there I can create the inner call and assign
//the correct parameter, but I can't seem to figure out how to wrap it in an
// new Action<serviceT> { my other expressions... }
// Types
var serviceT = Type.GetType(workOutMessage.interfaceType);
var actionT = typeof(Action<>).MakeGenericType(serviceT);
var envelopeT = Type.GetType(workOutMessage.methodArgTypes[0]);
// ServiceInvoker<T> Instantiation - Works
var serviceInvokerT = typeof(HubServiceInvoker<>).MakeGenericType(serviceT);
var serviceInvokerTMethod = serviceInvokerT.GetMethod("InvokeService");
var serviceInvokerTInstance = Activator.CreateInstance(serviceInvokerT, client.Id, "password", clientCert, serviceCert);
// Expression Type Params
var serviceTParam = Expression.Parameter(serviceT, "proxy");
var envelopeParam = Expression.Parameter(envelopeT, "envelope");
var envAssign = Expression.Assign(envelopeParam, Expression.Constant(workOutMessage.methodArgs[0]));
var methodCall = Expression.Call(serviceTParam, serviceT.GetMethod(workOutMessage.methodName), envelopeParam);
// var lambda = ...
// make new Action<serviceT> myAction = { proxy => proxy.someMethod(someParameter); };
serviceInvokerTMethod.Invoke(serviceInvokerTInstance, new object[] { lambda.Compile() });
Edit: The Service Invoker Method I pass this into to, to try and give the problem better context.
public void InvokeService(Action<T> handler)
{
T proxy = channelFactory.CreateChannel();
((IClientChannel)proxy).Faulted += ChannelFaulted;
ICommunicationObject obj2 = (ICommunicationObject)proxy;
try
{
using (new OperationContextScope((IContextChannel)proxy))
{
handler.Invoke(proxy);
}
}
finally
{
try
{
if (obj2.State != CommunicationState.Faulted)
{
obj2.Close();
}
}
catch
{
obj2.Abort();
}
}
}
Here is a full piece of code, in which I assume you only need a Func, not an Action.
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace HelloWorld
{
public class Service1
{
public Task ServiceMethod(string something)
{
return Task.Factory.StartNew(() => Console.WriteLine(something));
}
}
public class HubServiceInvoker<T> where T : new()
{
T t;
public HubServiceInvoker(string id, string password)
{
t = new T();
}
public void InvokeService(Func<T, Task> serviceInvoker)
{
Task task = serviceInvoker(t);
}
public static Func<T, Task> CompileInvoker(Expression expression, ParameterExpression serviceTParam)
{
Expression<Func<T, Task>> lambda = Expression.Lambda<Func<T, Task>>(expression, serviceTParam);
return lambda.Compile();
}
}
public class WorkOutMessage
{
public string interfaceType { get; set; }
public string[] methodArgTypes { get; set; }
public object[] methodArgs { get; set; }
public string methodName { get; set; }
}
static class Program
{
static void Main(string[] args)
{
WorkOutMessage workOutMessage = new WorkOutMessage()
{
interfaceType = "HelloWorld.Service1",
methodArgTypes = new string[] { "System.String" },
methodArgs = new object[] { "yeah it works!" },
methodName = "ServiceMethod"
};
InvokeService(workOutMessage);
Console.Read();
}
static void InvokeService(WorkOutMessage workOutMessage)
{
// Types
var serviceT = Type.GetType(workOutMessage.interfaceType);
// ServiceInvoker<T> Instantiation - Works
var serviceInvokerT = typeof(HubServiceInvoker<>).MakeGenericType(serviceT);
var serviceInvokerTMethod = serviceInvokerT.GetMethod("InvokeService");
var serviceCompileInvokerTMethod = serviceInvokerT.GetMethod("CompileInvoker");
var serviceInvokerTInstance = Activator.CreateInstance(serviceInvokerT, "id", "password");
// Expression Type Params
var serviceTParam = Expression.Parameter(serviceT, "proxy");
var methodCall = Expression.Call(serviceTParam, serviceT.GetMethod(workOutMessage.methodName), Expression.Constant(workOutMessage.methodArgs[0]));
serviceInvokerTMethod.Invoke(serviceInvokerTInstance, new object[] {
serviceCompileInvokerTMethod.Invoke(serviceInvokerTInstance, new object[] { methodCall, serviceTParam })
});
}
}
}
It was a little bit hard to understand what exactly is going on.
Perhaps, this will help you a little bit further:
// Helper.cs
public static Action<TType> Wrap<TType>(Delegate test)
{
return ret => test.DynamicInvoke();
}
var meth = typeof(Helper).GetMethod("Wrap");
var gmeth = meth.MakeGenericMethod(new[] { serviceT });
var genericAction = gmeth.Invoke(null, new object[] {
Expression.Lambda(methodCall).Compile(); });
Thanks to the hints from #Romain Hautefeuille, the key was to use my generic ServiceInvoker class to help me create the action that I needed without the need of using Expressions (woohoo).
// Execute Interface method from interface, methodName and methodArgs from message queue
var serviceT = Type.GetType(workOutMessage.interfaceType);
var serviceInvokerT = typeof(HubServiceInvoker<>).MakeGenericType(serviceT);
var serviceInvokerTMethod = serviceInvokerT.GetMethod("InvokeService");
var serviceInvokerCompileTMethod = serviceInvokerT.GetMethod("CompileServiceMethod");
var serviceInvokerTInstance = Activator.CreateInstance(serviceInvokerT, client.Id,
"password", clientCert, serviceCert);
// Works! and a lot simpler
serviceInvokerTMethod.Invoke(serviceInvokerTInstance, new object[] {
workOutMessage.correlationId,
serviceInvokerCompileTMethod.Invoke(serviceInvokerTInstance, new object[] {
workOutMessage.methodName,
workOutMessage.methodArgs })
});
And Finally the new method in the ServiceInvoker class (I wanted to avoid reflection in this class - for no particular reason - but it doesn't affect calling it normally).
public Action<T> CompileServiceMethod(string methodName, object[] methodArguments)
{
return new Action<T>(proxy =>
{
typeof(T).GetMethod(methodName).Invoke(proxy, methodArguments);
});
}

Cache reflected properties names

I have a method similar to this one:
static string GetVariableName<T>(Expression<Func<T>> expression)
{
var body = expression.Body as MemberExpression;
return body.Member.Name;
}
That give me the variables names. Everyone who mentions Reflection say It's bad for performance, So I want to cache the result so the reflection can occur only one single time for each var. Example:
GetVariableName(() => Model.Field1) // Does Reflection.
GetVariableName(() => Model.Field2) // Does Reflection.
GetVariableName(() => Model.Field1) // Uses Cache.
GetVariableName(() => Model.Field2) // Uses Cache.
I'm using this Util to log parameters And I want start using it to produce JQuery selectors in Asp.net Mvc3 application
$('#'+ #(GetVariableName(()=> Model.FieldName))).Val();
Any ideas?
Everyone who mentions Reflection say It's bad for performance
Sure, but in this case you already have the MemberInfo from the lambda expression. The compiler has already built the expression tree. You don't need to fetch it using reflection which is what is slow. What would have been expensive is the following:
static string GetVariableName(string expression)
{
// use reflection to find the property given the string and once you have the property
// get its name
...
}
That's how all the strongly typed helpers in ASP.NET MVC work. You don't need to cache anything if you use the strongly typed lambda expression version.
You should be able to do something like this...
class Foo {
public Foo() {
m_Field1Name = new Lazy<string>(() => GetVariableName(() => Field1));
m_Field2Name = new Lazy<string>(() => GetVariableName(() => Field2));
}
public int Field1 { get; set; }
public int Field2 { get; set; }
public string Field1Name {
get {
return m_Field1Name.Value;
}
}
readonly Lazy<string> m_Field1Name;
public string Field2Name {
get {
return m_Field2Name.Value;
}
}
readonly Lazy<string> m_Field2Name;
public static string GetVariableName<T>(Expression<Func<T>> expression) {
var body = expression.Body as MemberExpression;
return body.Member.Name;
}
}
Benchmarking the cached names versus non-cached shows significant difference...
class Program {
static void Main(string[] args) {
var foo = new Foo();
const int count = 1000000;
var sw = new Stopwatch();
sw.Restart();
for (int i = 0; i < count; ++i) {
string name1 = foo.Field1Name;
string name2 = foo.Field2Name;
}
sw.Stop();
Console.Write("Cached:\t\t");
Console.WriteLine(sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i) {
string name1 = Foo.GetVariableName(() => foo.Field1);
string name2 = Foo.GetVariableName(() => foo.Field2);
}
sw.Stop();
Console.Write("Non-cached:\t");
Console.WriteLine(sw.Elapsed);
}
}
This prints:
Cached: 00:00:00.0176370
Non-cached: 00:00:12.9247333
Have you considered using attributes? You could reflect over the model once and cache those results instead.
[AttributeUsage(AttributeTargets.Property, AllowMultiple= false)]
class JQueryFieldNameAttribute : Attribute {
public string Name { get; private set; }
public JQueryFieldNameAttribute(string name)
{
Name = name;
}
}
class Model {
[JQueryFieldName("#clientid")]
public string Foo { get; set; }
}
void Main()
{
var type = typeof(Model);
var attributes = type.GetProperties()
.SelectMany (t => t.GetCustomAttributes(typeof(JQueryFieldNameAttribute), true));
var cache = new Dictionary<int, IEnumerable<JQueryFieldNameAttribute>>();
// Cache results for this type only
cache.Add(type.GetHashCode(), attributes);
foreach (JQueryFieldNameAttribute a in attributes)
{
Console.WriteLine (a.Name);
}
}

Categories