Can I use Expression.Call on Generic and Static Methods? - linq

I'm trying to use Expression.Call on a generic, static Method.
Unfortunately, there is no signature of the Call Method allowing to give generic type arguments AND a method info argument.
Is this possibly in any way?
What I'm concretely trying to do is to write a helper class that can sort an IEnumerable(DataRow) via Linq dynamically.
Unfortunately, I have to use the DataRowExtensions to get the Field I want to sort in the Lambda expression.
The original code comes from http://aonnull.blogspot.de/2010/08/dynamic-sql-like-linq-orderby-extension.html.
The (experimental) piece of code looks at the moment as follows:
//T is DataRow
Type type = typeof(T);
IEnumerable<MethodInfo> extensions = GetExtensionMethods(Assembly.GetAssembly(typeof(DataRowExtensions)), typeof(DataRow));
ParameterExpression arg = Expression.Parameter(typeof(DataRow), "x");
//at Position 0 there is T Field<T>(string)
MethodInfo mi = extensions.ToList()[0];
var methArg = Expression.Parameter(typeof(String), "\"" + orderByInfo + "\"");
MethodCallExpression expr = Expression.Call(null, mi, arg, methArg);
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), typeof(Object));
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
When Runtime comes to the Expression.Call Statement an Exception is thrown saying that the Field-Method is generic.

So, yes. When you get MethodInfo for Field method, you really get generic method, without specify what type for return value.
T Field<T>(string)
For solving, just use MakeGenericMethod from this method with needed type, like
MethodInfo mi = extensions.ToList()[0].MakeGenericMethod(typeof(object));
here mi already specify generic parameter and present function
object Field(string);
Also you a bit complicate your code, so you can a bit simplified it and get something like this
//T is DataRow
Type type = typeof(T);
IEnumerable<MethodInfo> extensions = GetExtensionMethods(Assembly.GetAssembly(typeof(DataRowExtensions)), type);//if T is DataRow not needed get typeof again
ParameterExpression arg = Expression.Parameter(typeof(DataRow), "x");
//at Position 0 there is T Field<T>(string)
MethodInfo mi = extensions.ToList()[0].MakeGenericMethod(typeof(object));//you can change object type to needed type
var methArg = Expression.Parameter(typeof(String), orderByInfo);//if orderByInfo already string, then not needed wrap it in quotes
LambdaExpression lambda = Expression.Lambda<Func<T,string,object>>(
Expression.Call(mi, arg, methArg), //call mi with args: arg, methArg
arg,methArg);//pass parameters
Sidenote: you can not specify name for parameter, in this case name would be generate automatically, like: Param_0,Param_1 and etc.
You anyway not use parameter name directly.

Related

Using special characters in Enum value

I'm refactoring an ASP.NET MVC application that contains a Grid that uses remote filtering, sorting and pagination, it currently uses a string to pass the comparison operator that should be applied, I'd like to change that into an Enum:
Public Class MyController
Inherits Controller
Public Function GetOrders(filterModels As List(Of FilterModel)) As JsonResult
'A member of FilterModel is of type EnumComparisonOperators here
...
End Function
End Class
Public Enum EnumComparisonOperators
<Description("=")>
Equals = 0
<Description("<>")>
NotEquals = 1
<Description("<=")>
LessThanOrEquals = 2
<Description(">")>
GreaterThan = 3
<Description(">=")>
GreaterThanOrEquals = 4
End Enum
In the View:
//In the real code, my ajax call is in a callback from a third party
//component that just passes these loadOptions
var loadOptions = {
filterModel: {
operator: "=" //Replacing this string with "Equals" causes the code to work
//But my application logic needs a "=" sign, so I'd like to avoid
//converting back and forth
}
};
//The exception gets thrown the server when it receives this post call
$.post("/My/GetOrders", loadOptions);
My problem is that this results in an exception (= is not a valid value for EnumComparisonOperators.) as the calling grid component uses the string "=" for the "equals" operation and the controller doesn't parse that automatically, so my question is:
Is there a way for me to change/decorate/configure the Enum, so that "=" is recognized by the controller as a valid value as opposed to "Equals".
So in essence I'm trying to achieve the behavior I would get if = were the name of my enum's value, but = is a special character so I used Equals and am looking for configuration that would make it behave like =, that means, parsing and serialization should use =
The exception "= is not a valid value for EnumComparisonOperators" indicates that you're passing string which doesn't recognized as proper enum value (which contains integer indexes). You can keep <Description> attributes for each enum members (because you can't use operator symbols as enum member like EnumComparisonOperators.= or EnumComparisonOperators.<=), but it's necessary to write your own function to set enum member value from operator key in JSON using reflection like example below (adapted from this reference):
Public Function GetDescription(Of T)(ByVal value As T) As String
Dim field As FieldInfo = value.[GetType]().GetField(value.ToString())
Dim attributes As DescriptionAttribute() = CType(field.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
If attributes IsNot Nothing AndAlso attributes.Length > 0 Then
Return attributes(0).Description
Else
Return value.ToString()
End If
End Function
Public Function GetEnumValueFromOperator(Of T)(ByVal op As String) As T
Dim array As Array = [Enum].GetValues(GetType(T))
Dim list = New List(Of T)(array.Length)
For i As Integer = 0 To array.Length - 1
list.Add(CType(array.GetValue(i), T))
Next
Dim dic = list.[Select](Function(x) New With {
.Value = v,
.Description = GetDescription(x)
}).ToDictionary(Function(s) s.Description, Function(s) s.Value)
Return dic(op)
End Function
Afterwards, call the function above inside controller action (depending on your current implementation, these codes are subject to change):
Model
Public Class FilterModel
Public Property operator As String
' other properties
End Class
Controller
<HttpPost()>
Public Function GetOrders(filterModels As List(Of FilterModel)) As JsonResult
' check against null or zero length (filterModels.Count = 0) first
For Each fm As FilterModel In filterModels
Dim selectedOperator = GetEnumValueFromOperator(Of EnumComparisonOperators)(fm.operator)
Select Case selectedOperator
Case 0 ' Equals
' do something
End Select
Next
' other stuff
Return Json(...)
End Function
See also this fiddle for another usage example.
Note: Another available alternative is using EnumMemberAttribute like <EnumMember(Value := "=")> for every enum members and create a function to read that value as described in this issue.

Spring AOP get method parameter value based on parameter name

Is it possible to get the method parameter value based on parameter name in Spring AOP.
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
method.getParameters().getName()
// possible to get the paramater names
This approach will get parameter names, not value.
proceedingJoinPoint.getArgs()
will return values not names
Then is it possible to get the value based on a parameter name?
As I searched everywhere does not exist a function that gives parameter value by name and I wrote a simple method that makes this work.
public Object getParameterByName(ProceedingJoinPoint proceedingJoinPoint, String parameterName) {
MethodSignature methodSig = (MethodSignature) proceedingJoinPoint.getSignature();
Object[] args = proceedingJoinPoint.getArgs();
String[] parametersName = methodSig.getParameterNames();
int idx = Arrays.asList(parametersName).indexOf(parameterName);
if(args.length > idx) { // parameter exist
return args[idx];
} // otherwise your parameter does not exist by given name
return null;
}
I searched for the same thing when I had to use AOP for logging function arguments and their values but it seems there is no direct way to get value based on argument name.
What I noticed however us that value returned by method.getParameters().getName() and proceedingJoinPoint.getArgs() was always in sync., i.e., for function
public void foo(String a, String b)
called as
foo("hello", "world");
method.getParameters().getName() returned ["a", "b"] and proceedingJoinPoint.getArgs() returned ["hello", "world"], in order. So you can iterate over the array by index and for each index i, the i'th argument name would correspond to i'th argument value.
I couldn't find a supporting documentation for this behavior but hey, this code has been running on production servers for about an year it never has produced incorrect result. Though I'd be glad if someone can link to a documentation of this behavior. You may even dig into reflectiion's code to verify this behavior.

how do I do foo[bar] (partially dynamic property access) in fable?

I have a fairly simple javascript method
(props,propName,componentName) => {
var value = props[propName];
const getOrSpread = name =>
props[name] || props.spread && props.spread[name];
// remainder of function code omitted
}
that is working in javascript land. I'm trying to convert it to fable but either I can get it to have a definitely exists property access to .spread or dynamic access to props[propName] but not both
module JsxHelpers =
type IReactProps =
abstract member spread : obj
let isfuncOrNullPropType (props:IReactProps) (propName:string) componentName =
let propsO :obj = box props
let value:obj = propsO?propName
let valueAttempt2:obj = (box props)?(propName)
// rest of translation not attempted yet
value
where if props is defined as IReactProps, then .spread works, but neither of the two possible let value lines compile.
or props is defined as obj and it says `This expression was expected to have type 'obj' but here has type ''a -> obj'
even the simplest object from the documentation doesn't appear to compile:
let isfuncOrNullPropType (props:obj) (propName:string) =
let value2:obj = props?propName
value2
using "fable-core": "^1.0.0-narumi-905"
You definitely need to put the prop name in parentheses according to the documentation. The compiler error you're getting is because props?(propName) returns type 'a -> obj. Apparently, the dynamic (?) operator returns an Applicable, and from the fable source:
/// DO NOT USE: Internal type for Fable dynamic operations
type Applicable = obj->obj
Perhaps try:
let value : obj = unbox<obj> (props?(propName))

How do I use [TypeArguments] with a constructor reference in Java 8?

Section 15.13 of the Java Language Specification for Java 8 describes this form of the method reference syntax for creating a constructor reference:
ClassType :: [TypeArguments] new
For example:
String s = "abc";
UnaryOperator<String> test0 = String::new; // String(String) constructor.
String s0 = test0.apply(s);
System.out.println("s0 = " + s0); // Prints "abc".
char[] chars = {'x','y','z'};
Function<char[], String> test1 = String::new; // String(char[]) constructor.
String s1 = test1.apply(chars);
System.out.println("s1 = " + s1); // Prints "xyz"
That all works fine, but it seems that absolutely anything (excluding primitives) can be also supplied for the [TypeArguments] and everything still works:
Here's a silly example to prove the point:
Function<String, String> test2 = String::<LocalDateTime, Thread[]>new; // Compiles !!!???
String s2 = test2.apply("123");
System.out.println("s2 = " + s2); // Prints "123"
A few questions arising:
[1] Since the String class doesn't even use generics, is it valid that the compiler allows the creation of that test2 constructor reference with those meaningless [TypeArguments]?
[2] What would be a meaningful example of using [TypeArguments] when creating a constructor reference?
[3] Under what conditions is it essential to specify [TypeArguments] when creating a constructor reference?
1 15.13.1. Compile-Time Declaration of a Method Reference
If the method reference expression has the form ClassType :: [TypeArguments] new, the potentially applicable methods are a set of notional methods corresponding to the constructors of ClassType.
...
Otherwise, the candidate notional member methods are the constructors of ClassType, treated as if they were methods with return type ClassType. Among these candidates, the methods with appropriate accessibility, arity (n), and type argument arity (derived from [TypeArguments]) are selected, as specified in ยง15.12.2.1.
JLS 15.12.2.1. Identify Potentially Applicable Methods
This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored.
2 Whenever a constructor is parameterized. I've never stumbled upon one.
public class Foo {
public <T> Foo(T parameter) {
...
Function<String, Foo> test = Foo::<String>new
3 When the compiler can't infer the type.

Expression.Block method gives different errors in c#

Let us have the following:
Func<string, int> counterOfChar = (myString) => {
Console.WriteLine("Here is my parameter "+myString);
return myString.Count();
};
I want to bring all expressions involved here , by defining them so:
Expression<Action<string>> first = (param) => Console.WriteLine("Here is my parameter "+param);
Expression<Func<string, int>> second = (param) => param.Count();
And then call Expression.Block(first, second); as an example .
I am struggling for a week now and I don't want to tell you how diverse are the errors received until this moment.
Can someone write the corresponding Block and lambda expression for the delegate, but not going deep into ex: Method.Call ? Just stick to expressions !?
Thank you!
Expression<Action<string>> first = (param) => Console.WriteLine("Here is my parameter " + param);
Expression<Func<string, int>> second = (param) => param.Length; // .Count() is useless here!
Expression<Func<string, int>> third =
Expression.Lambda<Func<string, int>>(
Expression.Block(first.Body,
Expression.Invoke(second, first.Parameters[0])),
first.Parameters[0]);
var f = third.Compile();
var r1 = f("Hello");
"merging" two Expressions is always a little complex, because the two param of the two expressions are "different". They aren't the same param (it's like one is param1 and the other is param2). Here we resolve it by reusing the first parameter of the first expression as the parameter of the "new" expression and Expression.Invoke the other expression.
Without cheating, we could have
var par = Expression.Parameter(typeof(string));
Expression<Func<string, int>> third =
Expression.Lambda<Func<string, int>>(
Expression.Block(
Expression.Invoke(first, par),
Expression.Invoke(second, par)),
par);
var f = third.Compile();
var r1 = f("Hello");
where we introduce a new parameter par and we Expression.Invoke the other two expressions.
Note that Entity Framework doesn't support Expression.Invoke. In this case you can use a parameter rewriter (something like this.)

Resources