I am struggling with DynamicExpression.ParseLambda and string-interpolation
The following ParseLambda fails on the $ character.
Can anyone see why?
private static void Main()
{
var result = ExecuteJob("parameter.Trim()", " TheVale");
Console.WriteLine(result);
}
static string ExecuteJob(string job, string parameter)
{
//var result = new Func<string, string>(j => $"{parameter.Trim()}");
//return result(parameter);
var expression = $"$\"{{{job}}}\"";
var p = Expression.Parameter(typeof(string), nameof(parameter));
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, typeof(string), expression);
return (e.Compile().DynamicInvoke(parameter) ?? "").ToString();
}
Related
Helo,
i have a strange behavior in Visual Studio.
My code is a compiling at runtime, in VS it
workts fine but if i start the programm from
release-folder the compiled dll seems to be blocked,
what is not that unusal but why does VS dont say that?
Can some one tell me also how to unload a compiled dll
in runtime?
VS:
Release-Folder:
My Test Code here:
static void Main(string[] args)
{
var property = "Value";
var key = "MyKey";
var binding = string.Format("{0}.{1}", key, property);
var dllName = string.Format("Condition_{0}_{1}.dll", key, property);
var input = "65535";
var condition = "Convert.ToInt64(input) > 0xFFFF ? 0 : 501";
for (var i = 0; i < 5; i++)
{
try
{
var conditionCompiled = BuildCondition(key, property, condition);
Type moduleType = null;
if (conditionCompiled.Errors.HasErrors)
{
if (conditionCompiled.Errors[0].ErrorNumber != "CS0042")
throw new ConditionCompileException(conditionCompiled.Errors[0].ErrorText);
var assemblyPath = Path.Combine(Directory.GetCurrentDirectory(), dllName);
var assembly = Assembly.LoadFile(assemblyPath);
moduleType = assembly.GetType("DynaCore.ConditionRunner");
}
else
{
var module = conditionCompiled.CompiledAssembly.GetModules()[0];
moduleType = module.GetType("DynaCore.ConditionRunner");
}
var method = moduleType.GetMethod("RunCondition");
var value = method.Invoke(null, new object[] { input });
Console.WriteLine("DynaCore.ConditionRunner.RunCondition({0}) => {1}", input, value);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
if (e.InnerException != null)
Console.WriteLine(e.InnerException.Message);
}
}
Console.ReadLine();
}
private static CompilerResults BuildCondition(string name, string property, string condition)
{
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, string.Format("Condition_{0}_{1}.dll", name, property), true);
parameters.GenerateExecutable = false;
var results = csc.CompileAssemblyFromSource(parameters, string.Format(
#" using System.Linq;
using System;
using DESFireSDK.Dependency;
namespace DynaCore
{{
class ConditionRunner
{{
public static object RunCondition(string input)
{{
return {0};
}}
}}
}}"
, condition));
return results;
}
I wrote a function to convert LocalDeclaration's to Global Resources. Right now I'm replacing with each definition with a property, but I want to replace it with a property using the new syntax =>
public PropertyDeclarationSyntax ConvertToResourceProperty(string resouceClassIdentifier, string fieldName, string resourceKey, CSharpSyntaxNode field)
{
var stringType = SyntaxFactory.ParseTypeName("string");
var resourceReturnIdentifier = SyntaxFactory.IdentifierName(resouceClassIdentifier + "." + resourceKey);
var returnResourceStatement = SyntaxFactory.ReturnStatement(resourceReturnIdentifier).NormalizeWhitespace();
var getRescourceBlock = SyntaxFactory.Block(returnResourceStatement);
var getAccessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration, getRescourceBlock).WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);
var propertyDeclaration = SyntaxFactory.PropertyDeclaration(stringType, fieldName).AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)).NormalizeWhitespace();
propertyDeclaration = propertyDeclaration.AddAccessorListAccessors(getAccessor).WithAdditionalAnnotations(Formatter.Annotation);
SyntaxTrivia[] leadingTrivia = field.GetLeadingTrivia().ToArray() ?? new[] { SyntaxFactory.Whitespace("\t") };
return propertyDeclaration.WithTrailingTrivia(SyntaxFactory.Whitespace("\r\n"))
.WithLeadingTrivia(leadingTrivia)
.WithAdditionalAnnotations(Simplifier.Annotation);
}
This code create a property like so:
public static string LocalResourceName
{
get{ return Resources.LocalResourceName; }
}
I would like it to make the property like so:
public static string LocalResourceName =>Resources.LocalResourceName;
I'm not too sure what will create an expression bodied property from the syntaxfactory? Can anyone point me to the right method?
After scouring the internet I've found a way to do it. Why is there no documentation for roslyn?
public PropertyDeclarationSyntax ConvertToResourceProperty(string resouceClassIdentifier, string fieldName, string resourceKey, CSharpSyntaxNode field)
{
var stringType = SyntaxFactory.ParseTypeName("string");
var resourceClassName = SyntaxFactory.IdentifierName(resouceClassIdentifier);
var resourceKeyName = SyntaxFactory.IdentifierName(resourceKey);
var memberaccess = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, resourceClassName, resourceKeyName);
var propertyLambda = SyntaxFactory.ArrowExpressionClause(memberaccess);
var propertyDeclaration = SyntaxFactory.PropertyDeclaration(new SyntaxList<AttributeListSyntax>(), new SyntaxTokenList(),
stringType, null, SyntaxFactory.Identifier(fieldName), null,
propertyLambda, null, SyntaxFactory.Token(SyntaxKind.SemicolonToken))
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword),
SyntaxFactory.Token(SyntaxKind.StaticKeyword)).WithAdditionalAnnotations(Formatter.Annotation).NormalizeWhitespace();
return propertyDeclaration.WithTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed)
.WithLeadingTrivia(field.GetLeadingTrivia().ToArray())
.WithAdditionalAnnotations(Simplifier.Annotation);
}
I have a string string input; with some code (all below is in that string)
var x = s.IndexOf("a");
return String.Format(s, x);
Now, I would like to achieve following scenario:
Func<string, string> f = Compile(input);
var test = "dcba - {0}";
var result = f(test);
// result = "dcba - 3";
I assume, that the actual T1, TResult are known (here: string, string), and that input is named "s". I can achieve it this way:
var input = "var x = s.IndexOf(\"a\"); return String.Format(s, x);";
var containerClass = #"using System; class TempClass {{ public string temp_func(string s){{ {0} }} }}";
var code = String.Format(containerClass, input);
// Create a new instance of the C# compiler
var compiler = new CSharpCodeProvider();
var params = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
params.ReferencedAssemblies.Add("System.dll");
var results = compiler.CompileAssemblyFromSource(params, code);
Func<string, string> f;
if (results.Errors.Count == 0)
{
f = s =>
{
var myClass = results.CompiledAssembly.CreateInstance("TempClass");
return (string) myClass.GetType().
GetMethod("temp_func").
Invoke(myClass, new object[] {s});
};
// test:
Console.WriteLine(f(Console.ReadLine()));
}
But it is fairly complicated way. Is there any way to simplify this, if I know that I just want a Func<T1, TResult>, not a whole compiled assembly, instancing classes (or calling a static method on one)?
I can take this code, of course, and dress it nicely - wrap it in a generic class, get T1, TResult type names to put into the TempClass template (String.Format("public {0} temp_func({1} s)",typeof(TResult).Name, typeof(T1).Name);), but it has a feel of greasing an axle of a square wheel to make ride smoother...
I went with something like this:
public class DynamicFunction
{
private static int _counter = 0;
private const string ClassBody = "{2} public static class DynamicFunctionHost{0} {{ {1} }}";
private const string ClassName = "DynamicFunctionHost{0}";
private const string FunctionName = "func";
private const string T1FuncBody = "public static {1} func({0} param1){{ {2} }}";
public static Func<T1, TResult> Get<T1, TResult>(string funcBody, string[] referenced, string[] usingNs)
{
var code = String.Format(ClassBody, _counter,
String.Format(T1FuncBody, typeof (T1).Name, typeof (TResult).Name, funcBody),
String.Join("\n", usingNs.Select(r => String.Format("using {0};", r))));
var result = Compile(code, referenced);
var host =
result.CompiledAssembly.DefinedTypes.Single(
typeinfo => typeinfo.FullName.Equals(String.Format(ClassName, _counter)));
++_counter;
return input => (TResult) host.GetMethod(FunctionName).Invoke(null, new object[] { input });
}
private static CompilerResults Compile(string code, string[] referenced)
{
var compiler = new CSharpCodeProvider();
var parameters = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
foreach (var r in referenced)
parameters.ReferencedAssemblies.Add(r);
var results = compiler.CompileAssemblyFromSource(parameters, code);
if (results.Errors.Count == 0) return results;
// else
var e = new ArgumentException("Errors during compilation", "code");
e.Data.Add("Errors", results.Errors);
throw e;
}
}
The use is fairly simple then:
var f = DynamicFunction.Get<string, string[]>("return param1.ToCharArray()", new []{"System.dll","System.Core.dll"}, new []{"System"});
var x = f("abcd"); // =[a,b,c,d]
I have a rather complicated issue. I am trying to get a unique key from a method and its formal and actual parameters. The goal of the method, is to take a method call, and return a unique key based on 1) The name of the class and method and 2) The name and values of the parameters it is called with.
The method looks like this (sorry for all the details, but I can't find a sensible way to make the example smaller yet still explain my problem)
public class MethodKey
{
public static string GetKey<T>(Expression<Func<T>> method, params string[] paramMembers)
{
var keys = new Dictionary<string, string>();
string scope = null;
string prefix = null;
ParameterInfo[] formalParams = null;
object[] actual = null;
var methodCall = method.Body as MethodCallExpression;
if (methodCall != null)
{
scope = methodCall.Method.DeclaringType.FullName;
prefix = methodCall.Method.Name;
IEnumerable<Expression> actualParams = methodCall.Arguments;
actual = actualParams.Select(GetValueOfParameter<T>).ToArray();
formalParams = methodCall.Method.GetParameters();
}
else
{
// TODO: Check if the supplied expression is something that makes sense to evaluate as a method, e.g. MemberExpression (method.Body as MemberExpression)
var objectMember = Expression.Convert(method.Body, typeof (object));
var getterLambda = Expression.Lambda<Func<object>>(objectMember);
var getter = getterLambda.Compile();
var m = getter();
var m2 = ((System.Delegate) m);
var delegateDeclaringType = m2.Method.DeclaringType;
var actualMethodDeclaringType = delegateDeclaringType.DeclaringType;
scope = actualMethodDeclaringType.FullName;
var ar = m2.Target;
formalParams = m2.Method.GetParameters();
//var m = (System.MulticastDelegate)((Expression.Lambda<Func<object>>(Expression.Convert(method.Body, typeof(object)))).Compile()())
//throw new ArgumentException("Caller is not a method", "method");
}
// null list of paramMembers should disregard all parameters when creating key.
if (paramMembers != null)
{
for (var i = 0; i < formalParams.Length; i++)
{
var par = formalParams[i];
// empty list of paramMembers should be treated as using all parameters
if (paramMembers.Length == 0 || paramMembers.Contains(par.Name))
{
var value = actual[i];
keys.Add(par.Name, value.ToString());
}
}
if (paramMembers.Length != 0 && keys.Count != paramMembers.Length)
{
var notFound = paramMembers.Where(x => !keys.ContainsKey(x));
var notFoundString = string.Join(", ", notFound);
throw new ArgumentException("Unable to find the following parameters in supplied method: " + notFoundString, "paramMembers");
}
}
return scope + "¤" + prefix + "¤" + Flatten(keys);
}
private static object GetValueOfParameter<T>(Expression parameter)
{
LambdaExpression lambda = Expression.Lambda(parameter);
var compiledExpression = lambda.Compile();
var value = compiledExpression.DynamicInvoke();
return value;
}
}
Then, I have the following test, which works OK:
[Test]
public void GetKey_From_Expression_Returns_Expected_Scope()
{
const string expectedScope = "MethodNameTests.DummyObject";
var expected = expectedScope + "¤" + "SayHello" + "¤" + MethodKey.Flatten(new Dictionary<string, string>() { { "name", "Jens" } });
var dummy = new DummyObject();
var actual = MethodKey.GetKey(() => dummy.SayHello("Jens"), "name");
Assert.That(actual, Is.Not.Null);
Assert.That(actual, Is.EqualTo(expected));
}
However, if I put the () => dummy.SayHello("Jens") call in a variable, the call fails. Because I then no longer get a MethodCallExpression in my GetKey method, but a FieldExpression (subclass of MemberExpression. The test is:
[Test]
public void GetKey_Works_With_func_variable()
{
const string expectedScope = "MethodNameTests.DummyObject";
var expected = expectedScope + "¤" + "SayHello" + "¤" + MethodKey.Flatten(new Dictionary<string, string>() { { "name", "Jens" } });
var dummy = new DummyObject();
Func<string> indirection = (() => dummy.SayHello("Jens"));
// This fails. I would like to do the following, but the compiler
// doesn't agree :)
// var actual = MethodKey.GetKey(indirection, "name");
var actual = MethodKey.GetKey(() => indirection, "name");
Assert.That(actual, Is.Not.Null);
Assert.That(actual, Is.EqualTo(expected));
}
The Dummy class SayHello method definitions are trivial:
public class DummyObject
{
public string SayHello(string name)
{
return "Hello " + name;
}
public string Meet(string person1, string person2 )
{
return person1 + " met " + person2;
}
}
I have two questions:
Is there any way to send the variable indirection to MethodKey.GetKey, and get it as a MethodCallExpression type?
If not, how can I get the name and value of the method supplied if I get a MemberExpression instead? I have tried a few bits in the "else" part of the code, but haven't succeeded.
Any help is appreciated.
Thanks in advance, and sorry for the long post.
The problem is you are putting it into the wrong type of variable. Your method expects Expression<Func<T>> and you are using a variable of type Func<string> to store it. The following should fix your problem:
Expression<Func<string>> foo = () => dummy.SayHello("Jens");
var actual = MethodKey.GetKey<string>(foo, "name");
converting a .net Func<T> to a .net Expression<Func<T>> discusses the differences between a Func and an Expression<Func> and converting between the two and at a glance it says don't. The compiler makes them into totally different things. So make it the right thing at compile time and it should work fine.
If this isn't an option then possibly an overload that takes a Func instead of an Expression might work for you.
Note that in both cases I would pass the variable directly rather than trying to make it into a new expression in your call.
I have a simple method which retrieves a table from an azure mobile service.
public static async List<T>GetDataFromListTable<T>()
{
var data = await MobileService.GetTable<T>().ToListAsync();
return data.Count != 0 ? data : null;
}
This works fine.
What I am trying to do is have another method that takes a parameter name which is returned from the service and return the value of that parameter. So far I have this
public static async Task<T> GetDataFromTable<T>(string paramName)
{
var k = Activator.CreateInstance(typeof(T));
var members = typeof(T).GetProperties().Select(t=>t.Name).ToList();
if (!members.Contains(paramName))
return (T)k;
var mn = typeof(T).GetProperties()[members.IndexOf(paramName)];
var data = GetDataFromListTable<T>();
var retval = data.Select(t => t.mn);
}
The issue is obviously that I can't do the Linq query as T doesn't contain mn. I can also not use
var retval = data.Select(t=>t.paramName);
as paramname is a just a string representation of a member within a class.
In a nutshell...
method 1 has the parameter name, grabs a list from method 2. From the returned list in method 2, find the parameter name and return the associated value.
Is there a way to do what I'm trying to do?
You can do:
var retval = data.Select(t => mn.GetGetMethod().Invoke(t, null));
or
var retval = data.Select(t => mn.GetValue(t, null));
You can also simplify your code with something like this (not tested, sorry):
public static async Task<T> GetDataFromTable<T>(string paramName)
{
var k = Activator.CreateInstance(typeof(T));
var mn = typeof(T).GetProperty(paramName);
if (mn == null)
return (T)k;
var data = GetDataFromListTable<T>();
var retval = data.Select(t => mn.GetGetMethod().Invoke(t, null));
...
}
I think using expression trees would be more convenient since you're working with collections. Your method signature needs to incorporate the types T and TResult since it is using Select which returns an IEnumerable<TResult>.
public static async Task<IEnumerable<TResult>> SelectData<T, TResult>(
string propertyName
)
{
if(string.IsNullOrWhiteSpace(propertyName))
{
return Enumerable.Empty<TResult>();
}
var dataTask = GetTableData<T>();
var tType = Expression.Parameter(typeof(T), "t");
var property = Expression.Property(tType, propertyName);
var selectExpression =
Expression.Lambda<Func<T, TResult>>(property, tType)
.Compile();
return (await dataTask).Select(selectExpression);
}
Isn't it possible to do this
var retval = data.Select(t => mn.GetValue(t, null));