How to create NotStartsWith Expression tree - c#

I'm using jqGrid to display some data to users. jqGrid has search functionality that does string compares like Equals, NotEquals, Contains, StartsWith, NotStartsWith, etc.
When I use StartsWith I get valid results (looks like this):
Expression condition = Expression.Call(memberAccess,
typeof(string).GetMethod("StartsWith"),
Expression.Constant(value));
Since DoesNotStartWith doesn't exist I created it:
public static bool NotStartsWith(this string s, string value)
{
return !s.StartsWith(value);
}
This works, and I can create a string and call this method like so:
string myStr = "Hello World";
bool startsWith = myStr.NotStartsWith("Hello"); // false
So now I can create/call the expression like so:
Expression condition = Expression.Call(memberAccess,
typeof(string).GetMethod("NotStartsWith"),
Expression.Constant(value));
But I get a ArgumentNullException was unhandled by user code: Value cannot be null.
Parameter name: method error.
Does anyone know why this doesn't work or a better way to approach this?

You're checking for method NotStartsWith on type string, which doesn't exist. Instead of typeof(string), try typeof(ExtensionMethodClass), using the class where you put your NotStartsWith extension method. Extension methods don't actual exist on the type itself, they just act like they do.
Edit: Also rearrange your Expression.Call call like this,
Expression condition = Expression.Call(
typeof(string).GetMethod("NotStartsWith"),
memberAccess,
Expression.Constant(value));
The overload you are using expects an instance method, this overload expects a static method, based on the SO post you referred to. See here, http://msdn.microsoft.com/en-us/library/dd324092.aspx

i know the ask was answered, but another approach is available and simple:
Expression condition = Expression.Call(memberAccess,
typeof(string).GetMethod("StartsWith"),
Expression.Constant(value));
condition = Expression.Not(condition);
and... done! just have to negate the expression.

Related

Add inline variables to a theory xUnit

I'm trying to use a variable as InlineData when using xUnit.
It looks like this:
static string home = "test";
[Theory]
[InlineData(home)]
public void AddTest(string location)
{
Assert.True(LocationIs(location));
}
But I'm getting the error: "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type"
Is there any way for me to do what I'm trying? Or do I need to just hardcode the inline data.
You could do it with const string home = "test" because that would be a constant expression.
You could also make use of the MemberData attribute to point to something that does yield return new object[]{ "test" }; which is more convoluted in this case, but more flexible in terms of not having to be constant, and allowing you to yield many such arrays to have the test done repeatedly on different sets of data.

What is the outcome of "() => true"

I'm reviewing another person's code and can't ask him... What does that line of C# code do?
It's a lambda expression that takes no parameter and returns true.
The equivalent anonymous delegate is:
delegate() { return true; };
Most likely the method requires a parameter of type Func<bool>, which is a generic delegate with the same signature as above code.
EDIT:
As noted by cdhowie, the above lambda can also be evaluated to an expression tree of type Expression<Func<bool>>.
Here's the equivalent expression tree:
var body = Expression.Constant(true);
Expression<Func<bool>> returnsTrueExpression = Expression.Lambda<Func<bool>>(body);
You can 'convert' it to an actual delegate by calling Compile()
Func<bool> returnsTrueFunc = returnsTrueExpression.Compile();
This is a lambda expression that always return true. This is a delegate that has functionality similar to this method
bool Test(){
return true;
}
The code reminds me of when you may want to stub or mock values in the early stages of creating unit tests.
You could have a class that has a method like:
bool result = SomeClass.RunSomeImportantProcess(Func<bool> process)
and in your tests you might want to do something as a stub like
Assert.IsTrue(SomeClass.RunSomeImportantProcess(() => true));
Its a lambda expression which doesn't take any parameter but returns true. Whether its required or not, you would have to provide more info to determine.

extending SqlMethods.Like to support property name

I'm trying to extend SqlMethods.Like method to support property name rather than property value, i wrote the following extension method :
public static bool Like(this object obj, string propertyName, string pattern)
{
var properties = obj.GetType().GetProperties().Select(p => p.Name);
if(!properties.Contains(propertyName))
throw new Exception(string.Format("Object does not contain property:{0}", propertyName));
return SqlMethods.Like(obj.GetType().GetProperty(propertyName).GetValue(obj, null).ToString(), pattern);
}
however the method throws the following exception :
Method 'Boolean Like(System.Object, System.String, System.String)' has no supported translation to SQL.
how can i write an extension method with transaction to SQL support ?
I found this answer from RichardD that is exactly the correct answer. Reposting for clarity, but original is linked below.
using System;
using System.Linq;
using System.Linq.Expressions;
public static class Extensions
{
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, string propertyName, string pattern)
{
if (null == source) throw new ArgumentNullException("source");
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(typeof(T), "a");
var prop = Expression.Property(a, propertyName);
var body = Expression.Call(typeof(SqlMethods), "Like", null, prop, Expression.Constant(pattern));
var fn = Expression.Lambda<Func<T, bool>>(body, a);
return source.Where(fn);
}
}
...
.WhereLike("Description", "%a%b%c%"));
The solution uses expression trees, but all advanced LinqToSql operations will require familiarity with that.
From: http://forums.asp.net/p/1488418/3503874.aspx
What you want to do does not seem to make sense in the contxt of what SqlMethods.Like actually does. When you pass in a property of a class you are essentially telling it to translate that into the equivelent field in the SQL query. e.g.
var result = from names in db.Names
where SqlMethods.Like(names.FullName, '%Smith%')
select names;
would translate to something like:
SELECT *
FROM Names
WHERE Fullname LIKE '%Smith%'
(in practice it would be different using parameters and sp_executeSQL but coneptually that is what it would do).
If you want to pass in the name of a property what does that mean in terms of SQL, conceptually it makes no sense e.g.
SELECT *
FROM Names
WHERE --what would go here-- LIKE '%Smith%'
As such you are not going to be able to create a Linq To SQL method that creates nonsense SQL.
What are you actually trying to do, the chance is that you are going about it completely the wrong way.
Edit:hmm from your comment i think i understand what you want to do, in essense you want to be able to specify the column you are doing a LIKE comparison with at run time. You cannot do it exactly. You could use a stored procedure that used dynamic SQL and took a string parameter for the column. You could then expose this as a method on your data context class.

How do I get a value of a reference type in an Expression?

I have this method:
public void DoSomething<T>(Expression<Func<T, object>> method)
{
}
If this method is called like this:
DoSomething(c => c.SomeMethod(new TestObject()));
... how do I get the value of the parameter that was passed into SomeMethod()?
If the parameter is a value type, this works:
var methodCall = (MethodCallExpression)method.Body;
var parameterValue = ((ConstantExpression)methodCall.Arguments[0]).Value;
However, when I pass in a reference type, methodCall.Arguments[0] is a MemberExpression, and I can't seem to figure out how to write code to get the value out of it.
Here is the answer (inspired by Akash's answer):
LambdaExpression lambda = Expression.Lambda(methodCall.Arguments[0]);
var compiledExpression = lambda.Compile();
return compiledExpression.DynamicInvoke();
You will have to evaluate member expression manually, MemberExpression contains "Expression" which is the container object of Member specified, to do this you can crete Lamda of your arguement and compile and execute it.
LamdaExpression l = Expression.Lambda(methodCall.Arguments[0]);
var c = l.Compile();
var v = c.Invoke();
So whatever you pass, you will get it in "v" variable.
This isn't really a matter of value type or reference type - it's a matter of a constant expression or not-constant expression. I'm sure your existing code would fail if you called
DoSomething(c => c.SomeMethod(DateTime.Now));
as well.
Basically, the argument to the method is just an expression. It's not a value. You could potentially compile that expression and then execute it to get the value at that point in time, but it's important to understand that an expression isn't a value in itself. In the case of a constant expression it's easy, but taking the DateTime.Now example, by definition the evaluated value of the expression changes over time :)
What are you trying to do with the argument? What's the bigger picture here?
Firstly, what Jon said.
There are no values to get ahold of, it's all just expressions. What might be of interest is the NewExpression, which has a Constructor property; this property contains the reflected constructor that would be called if you compiled expression and ran the resulting delegate. You could manually invoke that constructor and get an instance of what the user was intending on instantiating.

Get Method Name Using Lambda Expression

I'm trying to get the name of a method on a type using a lambda expression. I'm using Windows Identity Foundation and need to define access policies with the type name with namespace as a resource and the method name as the action. Here is an example.
This is the type I would be getting the type name and method name from:
namespace My.OrderEntry {
public class Order {
public void AddItem(string itemNumber, int quantity) {}
}
}
This is how I would like to define the access policy through a DSL:
ForResource<Order>().Performing(o => o.AddItem).AllowUsersHaving(new Claim());
From that statement, I would like to get "My.OrderEntry.Order" as the resource and "AddItem" as the action. Getting the type name with namespace is no problem, but I don't think I can use a lambda for a method like I'm trying to do.
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Func<T, delegate???> action) {} //this is where I don't know what to define
Is this sort of thing even possible to do? Is there another way to do this sort of thing without using magic strings?
There are two ways to do this:
1: You could make overloads that take the various Func and Action delegates(eg Expression<Func<T, Func<TParam1,TParam2, TReturn>>. Note that your callers would need to specify the generic parameters explicitly, either in the method call or by creating the delegate. This would be used like this:
ForResource<Order>().Performing(o => new Action<string>(o.AddItem)).AllowUsersHaving(new Claim());
2: You could take an Expression<Action> that contains a method call, and parse out the MethodInfo being called from the expression tree. This would be used like this:
ForResource<Order>().Performing(o => { o.AddItem(null); }).AllowUsersHaving(new Claim());
It looks like this is what you are looking for if you want the name of the action delegate method passed in to the Performing function.
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Expression<Action<T, string, int>> action)
{
var expression = action.Body as MethodCallExpression;
string actionMethodName = string.Empty;
if (expression != null)
{
actionMethodName = expression.Method.Name;
}
// use actionMethodName ("AddItem" in the case below) here
}
This would allow you to call the method like this...
ForResource<Order>().Performing((o, a, b) => o.AddItem(a, b)).AllowUsersHaving(new Claim());
I recently did a thing at work where you defined the a method using a lambda, which the internal object then took the name of. You could use strings as well, or pass in a MethodInfo but the first one isn't really type safe (and typos are a big risk), and the latter is not very elegant.
Basically I had a method like this (this is not the exact method, it is a bit more advanced):
public void SetRequest(Request req, Expression<Func<Service, Func<long, IEnumerable<Stuff>>> methodSelector);
The key here is the "Expression" thing, this lets you "select" a method like this:
SetRequest(req, service => service.SomeMethodTakingLongReturningStuffs);
Method selector is made into a expression tree which you can then fetch different bits of data from. I don't recall exactly what the resulting tree looks like, it also depends on how your lambdas look.
You could pass it in as a Action instead, which doesn't force any return type. It is still a little messy though, because you have to pass some arguments to the method in order for it to compile.

Categories