I have a code like this;
class abc{
void A()
{
//Some to do statements
}
void B()
{
var obj=A();
}
void C()
{
var call=B();
}
}
I want to find the Invoked method name using roslyn.
like here o/p will be:
for method B :Invoked method A
for method C:Invoked method A
i want something like this:
root.DescendantNodes().OfType<InvocationExpressionSyntax>().Where(md => md.Identifier.ValueText.Equals(methodName)).FirstOrDefault();
but InvocationExpression doesn't contain Identifier to access.
How to get identifier name
I agree with SLaks and would add to his answer, if what you want is:
"I want the method invocation syntax nodes where the receiver syntax -- let me emphasize SYNTAX -- is a single identifier equal to some particular string"
then the query you want is something like
var root = tree.GetRoot();
var nodes = from node in root.DescendantNodes()
.OfType<InvocationExpressionSyntax>()
let id = node.Expression as IdentifierNameSyntax
where id != null
where id.Identifier.ValueText == methodName
select node;
But I think that is maybe not what you want. If what you want is "I want to know exactly which method is invoked regardless of whether it is written A(...) or Foo.Bar.A(...) then you don't want to be considering the syntax at all. You'll need to use the semantic analyzer to get the symbol associated with the invocation, and then check whether that symbol identifies the method you're interested in.
Are you primarily interested in a syntactic or a semantic analysis here? Roslyn does either, but you're only looking at syntax in the code you've presented.
If what you're looking for is a semantic analysis then you want to do something like this:
var tree = CSharpSyntaxTree.ParseText(code);
var c = CSharpCompilation.Create("asm.dll");
c = c.AddSyntaxTrees(tree);
var model = c.GetSemanticModel(tree);
string methodName = "A";
var root = tree.GetRoot();
var symbols = from node in root.DescendantNodes()
.OfType<InvocationExpressionSyntax>()
let symbol = model.GetSymbolInfo(node.Expression).Symbol as IMethodSymbol
where symbol != null
where symbol.Name = methodName
select symbol;
The reason InvocationExpressionSyntax does not have Identifier because it may have with this case var obj = this.A() so it's reason why InvocationExpressionSyntax will contain property Expression with type ExpressionSyntax (which may be IdentifierNameSyntax type),
1.So simple answer for your case is you can access property Expression like this.
foreach (var item in root.DescendantNodes()
.OfType<InvocationExpressionSyntax>())
{
var expr = item.Expression;
if (expr is IdentifierNameSyntax)
{
IdentifierNameSyntax identifierName = r as IdentifierNameSyntax; // identifierName is your method name
}
if (expr is MemberAccessExpressionSyntax)
{
MemberAccessExpressionSyntax memberAccessExpressionSyntax = r as MemberAccessExpressionSyntax;
//memberAccessExpressionSyntax.Name is your method name
}
}
2.but for exact lookup the invocation method is the same with method you declared you have to use Semantic information as in this example in Roslyn project
https://github.com/dotnet/roslyn/wiki/FAQ#how-do-i-find-all-calls-in-a-compilation-into-a-particular-namespace
You're misunderstanding the role of these nodes in the syntax tree.
You should use the Roslyn Syntax Visualizer in VS to see what the nodes for a method call actually look like.
In short: An InvocationExpression just means someExpression(some arguments). That expression can be a number of things, such as a constructor call, a member access, an array access, or any other expression that resolves to a method or delegate.
You need to check the Kind of the InvocationExpressionSyntax and figure out how you want to handle every possible expression.
Related
I have a CSharpSyntaxRewriter that overrides VisitMemberAccessExpression, inside that method, I am calling MemberAccessExpressionSyntax.WithName(), but the node it returns has a different SyntaxTree compared to the original node, this is a problem since it means an error is thrown when calling SemanticModel.GetSymbolInfo(node).
Is there a way to change the Name of a MemberAccessExpressionSyntax but still have a SyntaxTree that works with SemanticModel.GetSymbolInfo(node)?
My code is:
public sealed override SyntaxNode VisitNode(SyntaxNode node)
{
var nodeSyntax = (MemberAccessExpressionSyntax) node;
if (nodeSyntax.Name.ToString() == OldModifier && !HasSymbol(nodeSyntax, out _))
{
if (ModifierType == ModifierType.Damage)
nodeSyntax = nodeSyntax.WithName(IdentifierName($"GetDamage({NewModifier})"));
else
nodeSyntax = nodeSyntax.WithName(IdentifierName($"GetCritChance({NewModifier})"));
nodeSyntax = nodeSyntax.WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia());
}
return nodeSyntax;
}
(VisitNode is called from VisitMemberAccessExpression)
And here are images showing the difference in the SyntaxTree:
original:
After calling WithName:
There's a few ways to approach something like this:
Change Your Visit Method
Can you restructure your code to call VisitNode before you've done any changes to VisitMemberAccessExpression? For example can you go from:
var memberAccess = memberAccess.With...();
memberAccess = VisitNode(memberAccess);
return memberAccess;
to
var memberAccess = VisitNode(memberAccess);
memberAccess = memberAccess.With...();
return memberAccess;
Then it might mean that you are then visiting with the original node before you've done rewriting. Note this can still be tricky though if you are doing recursive stuff.
Use ReplaceNodes
There's a helper method you can use instead of a rewriter. This will call the function you pass to do rewriting at each step, but that function is handed both the original node in the original tree and the node after child nodes have been rewritten; you can use the original one to ask binding questions (since that's from the original tree) and consume the one that's been rewritten for recursive rewriting.
Break Your Problem into Two Steps
Do two walks: first get a list of all the places will need to update, add those SyntaxNodes to a HashSet or like, and then do the rewrite second where you are updating those places.
I would like to create the following expression dynamically:
e.Collection.Select(inner => inner.Property)
I created this code to do it, however I have an issue when I execute the expression call, someone knows what I'm doing wrong?
private static Expression InnerSelect<TInnerModel>(IQueryable source, ParameterExpression externalParameter, string complexProperty)
{
// Creates the expression to the external property. // this generates: "e.Collection".
var externalPropertyExpression = Expression.Property(externalParameter, complexProperty);
// Creates the expression to the internal property. // this generates: "inner => inner.Property"
var innerParameter = Expression.Parameter(typeof(TInnerModel), "inner");
var innerPropertyExpression = Expression.Property(innerParameter, "Property");
var innerLambda = Expression.Lambda(innerPropertyExpression, innerParameter);
return Expression.Call(typeof(Queryable), "Select", new [] { typeof(TInnerModel) }, externalPropertyExpression, innerLambda);
}
Error:
No generic method 'Select' on type 'System.Linq.Queryable' is
compatible with the supplied type arguments and arguments. No type
arguments should be provided if the method is non-generic.
So, first off, the primary problem is very simple. As the error message says, you haven't passed enough type arguments to Select. But when you fix that, you'll still have a problem, and that problem will be much harder for you to see and understand.
Let's dig into that.
You wish to represent this as an expression tree:
e.Collection.Select(inner => inner.Property)
Let's begin by rewriting it in its non-extension-method form.
Queryable.Select<A, B>(e.Collection, inner => inner.Property)
Where A is the collection member type and B is the type of Property.
Now, suppose you had this expression in your program. What would it actually do at runtime? It would construct an expression tree for the lambda and pass it to Queryable.Select. That is, it would do something like:
var innerParameter = parameterFactory(whatever);
var lambdaBody = bodyFactory(whatever);
var lambda = makeALambda(lambdaBody, innerParameter);
Queryable.Select<TInnerModel>(e.Collection, lambda);
Right? You with me so far?
Now, suppose we wish to translate this program fragment to an expression tree that could itself be the body of a lambda. That would be:
var theMethodInfoForSelect = whatever;
var receiverE = valueFactory(whatever);
var thePropertyInfoForCollection = whatever;
var theFirstArgument = propertyFactory(receiverE, thePropertyInfoForCollection);
...
Again, with me so far? Now, the crucial question: what is the second argument? It is NOT the value of lambda, which is what you are passing. Remember, what we are doing here is constructing an expression tree which represents the code that the compiler is generating for that thing, and the expression tree that is in lambda is not that. You're mixing levels!
Let me put it this way: the compiler is expecting "add one and three". You are passing 4. Those are very different things! One of them is a description of how to obtain a number and the other one is a number. You are passing an expression tree. What the compiler is expecting is a description of how to obtain an expression tree.
So: do you have to now write code that generates expression trees for all of lambda's construction code? Thank goodness no. We provided you a handy way to turn an expression tree into a description of how to produce an expression tree, which is the Quote operation. You need to use it.
So, what is the right sequence of events that you need to do to build your expression tree? Let's walk through it:
First, you'll need a ParameterExpression of the type of e, which you already have in hand. Let's suppose that is:
ParameterExpression eParam = Expression.Parameter(typeof(E), "e");
Next, you will need a method info for the Select method. Let's suppose you can correctly get that.
MethodInfo selectMethod = whatever;
That method takes two arguments, so let's make an array of argument expressions:
Expression[] arguments = new Expression[2];
You'll need a property info for your Collection property. I assume you can get that:
MethodInfo collectionGetter = whatever;
Now we can build the property expression:
arguments[0] = Expression.Property(eParam, collectionGetter);
Super. Next we need to start building that lambda. We need a parameter info for inner:
ParameterExpression innerParam = Expression.Parameter(typeof(Whatever), "inner");
We'll need a property info for Property, which I assume you can get:
MethodInfo propertyGetter = whatever;
Now we can build the body of the lambda:
MemberExpression body = Expression.Property(innerParam, propertyGetter);
The lambda takes an array of parameters:
ParameterExpression[] innerParams = { innerParam };
Build the lambda from the body and the parameters:
var lambda = Expression.Lambda<Func<X, int>>(body, innerParams);
Now the step you missed. The second argument is the quoted lambda, not the lambda:
arguments[1] = Expression.Quote(lambda);
Now we can build the call to Select:
MethodCallExpression callSelect = Expression.Call(null, selectMethod, arguments);
And we're done.
Give someone an expression tree and you give them an expression tree for a day; teach them how to find expression trees themselves and they can do it for a lifetime. How did I do that so fast?
Since I wrote the expression tree code generator, I had some immediate familiarity with the problem that you were likely to have. But that was ten years ago, and I did not do the above entirely from memory. What I did was I wrote this program:
using System;
using System.Linq.Expressions;
public interface IQ<T> {}
public class E
{
public IQ<X> C { get; set; }
}
public class X
{
public int P { get; set; }
}
public class Program
{
public static IQ<R> S<T, R>(IQ<T> q, Expression<Func<T, R>> f) { return null; }
public static void Main()
{
Expression<Func<E, IQ<int>>> f = e => S<X, int>(e.C, c => c.P);
}
}
Now I wished to know what code was generated by the compiler for the body of the outer lambda, so I went to https://sharplab.io/, pasted in the code, and then clicked on Results --> Decompile C#, which will compile the code to IL and then decompile it back to human-readable C#.
This is the best way I know of to quickly understand what the C# compiler is doing when it builds an expression tree, regardless of whether you know the compiler source code backwards and forwards. It's a very handy tool.
I am trying to use Expression Trees because based on description, that seems to be the most correct (performant, configurable) approach.
I expect to be able to craft a statement that gets the first item from the existingItems collection that matches the propertyNameToCompareOn value of the incomingItem.
I have a method with the following signature and simulated code body...
DetectDifferences<T>(List<T> incomingItems, List<T> existingItems)
{
var propertyNameToCompareOn = GetThisValueFromAConfigFile(T.FullName());
//does this belong outside of the loop?
var leftParam = Expression.Parameter(typeof(T), "left");
var leftProperty = Expression.Property(leftParam, identField);
var rightParam = Expression.Parameter(typeof(T), "right");
var rightProperty = Expression.Property(rightParam, identField);
//this throws the error
var condition = Expression.Lambda<Func<T, bool>>(Expression.Equal(leftProperty, rightProperty));
foreach (var incomingItem in incomingItems) //could be a parallel or something else.
{
// also, where am I supposed to provide incomingItem to this statement?
var existingItem = existingItems.FirstOrDefault(expression/condition/idk);
// the statement for Foo would be something like
var existingFoos = exsistingItems.FirstOrDefault(f => f.Bar.Equals(incomingItem.Bar);
//if item does not exist, consider it new for persistence
//if item does exist, compare a configured list of the remaining properties between the
// objects. If they are all the same, report no changes. If any
// important property is different, capture the differences for
// persistence. (This is where precalculating hashes seems like the
// wrong approach due to expense.)
}
}
At the marked line above, I get an "Incorrect number of parameters supplied for lambda declaration" InvalidOperationException. At this point I am just hacking crap together from the web and I really dont know what this wants. There are a bunch of overloads that VS can full my screen with, and none of the examples make sense from the articles on MSDN/SO.
PS - I dont really want an IComparer or similar implementation if it can be helped. I can do that with reflection. I do need to make this as rapid as possible, but allow it to be called for multiple types, hence the choice of expression trees.
When working with expression trees, it's important to first understand, in real code, what you want to do.
I always begin by first writing out (in static code) what the resulting expression looks like with real C# lambda syntax.
Based on your description, your stated goal is that you should be able to (dynamically) look up some property of the type T that gives some sort of quick comparison. How would you write this if both T and TProperty were both known at compile time?
I suspect it would look something like this:
Func<Foo, Foo, bool> comparer = (Foo first, Foo second) =>
first.FooProperty == second.FooProperty;
Right away we can see that your Expression is wrong. You don't need one input T, you need two!
It should also be obvious why you're getting the InvalidOperationException as well. You never supplied any parameters to your lambda expression, only the body. Above, 'first' and 'second' are the parameters provided to the lambda. You'll need to provide them to the Expression.Lambda()call as well.
var condition = Expression.Lambda<Func<T,T, bool>>(
Expression.Equal(leftProperty, rightProperty),
leftParam,
rightParam);
This simply uses the Expression.Lambda(Expression, ParameterExpression[]) overload for Expression.Lambda. Each ParameterExpression is the parameter that is used in the body. That's it. Don't forget to .Compile() your expression into a delegate if you want to actually invoke it.
Of course this doesn't mean that your technique will be necessarily fast. If you're using fancy expression trees to compare two lists with a naive O(n^2) approach, it won't matter.
Here's a method to make a property access expression;
public static Expression<Func<T, object>> MakeLambda<T>(string propertyName)
{
var param = Expression.Parameter(typeof(T));
var propertyInfo = typeof(T).GetProperty(propertyName);
var expr = Expression.MakeMemberAccess(param, propertyInfo);
var lambda = Expression.Lambda<Func<T, object>>(expr, param);
return lambda;
}
which you can use like this;
var accessor = MakeLambda<Foo>("Name").Compile();
accessor(myFooInstance); // returns name
Making your missing line
var existingItem = existingItems.FirstOrDefault(e => accessor(e) == accessor(incomingItem));
Be aware the == only works well for value types like ints; careful of comparing objects.
Here's proof the lambda approach is much faster;
static void Main(string[] args)
{
var l1 = new List<Foo> { };
for(var i = 0; i < 10000000; i++)
{
l1.Add(new Foo { Name = "x" + i.ToString() });
}
var propertyName = nameof(Foo.Name);
var lambda = MakeLambda<Foo>(propertyName);
var f = lambda.Compile();
var propertyInfo = typeof(Foo).GetProperty(nameof(Foo.Name));
var sw1 = Stopwatch.StartNew();
foreach (var item in l1)
{
var value = f(item);
}
sw1.Stop();
var sw2 = Stopwatch.StartNew();
foreach (var item in l1)
{
var value = propertyInfo.GetValue(item);
}
sw2.Stop();
Console.WriteLine($"{sw1.ElapsedMilliseconds} vs {sw2.ElapsedMilliseconds}");
}
As someone's also pointed out, though, the double-loop in the OP is O(N^2) and that should probably be the next consideration if efficiency is the driver here.
I almost got what I need but only one place where I stucked. I need to build fileCount = c.CPNDocs.Count() Dynamically in Lambda Expression. Code is below with comments what I am using to build Dynamic Lambda Expression.
var dColDefaultList = new List<String>() { "Download", "I_ID", "C_TYP", "C_LST_ACT" }; // <------- Columns I need in Lambdas Expression
ParameterExpression cParam = Expression.Parameter(typeof(CPNDBase), "c");
NewExpression newExp = Expression.New(typeof(DTDataModel));
List<MemberBinding> bindings = new List<MemberBinding>();
foreach (String sCol in dColDefaultList)
{
if (!String.Equals(sCol, "Download")) {
bindings.Add(GetMemberBinding(sCol, cParam, sCol));
}
else
{
bindings.Add(GetMemberBinding("fileCount", cParam, "CPNDocs.Count()")); // <-------need count of rows return from CPNDocs(Different Table) is a Object I recieved from Entity Relatioship
}
}
MemberInitExpression memberInitExpression = System.Linq.Expressions.Expression.MemberInit(newExp, bindings);
Expression<Func<CPNDBase, DTDataModel>> selector = (Expression<Func<CPNDBase, DTDataModel>>)BinaryExpression.Lambda(memberInitExpression, cParam);
// selector will be selector = {c => new DTDataModel() {fileCount = c.CPNDocs, I_ID = c.I_ID, C_TYP = c.C_TYP, C_LST_ACT = c.C_LST_ACT }}
// but I Need selector = {c => new DTDataModel() {fileCount = c.CPNDocs.Count(), I_ID = c.I_ID, C_TYP = c.C_TYP, C_LST_ACT = c.C_LST_ACT }}
// Question is How can I make fileCount = c.CPNDocs.Count() ?
var resultLm = finalFilteredCPNData.AsQueryable<CPNDBase>().Select(selector);
Above method is defined here :
static MemberBinding GetMemberBinding(string property, ParameterExpression param, string column)
{
MemberInfo memberInfo = typeof(DTDataModel).GetMember(property)[0];
MemberExpression memberExpression = LambdaExpression.PropertyOrField(param, column);
return System.Linq.Expressions.Expression.Bind(memberInfo, memberExpression);
}
Does anybody know how can I do this?
The Count() is not a property. It is an extension method implemented in a static class. This extension method is implemented at several places. Correct place depends on what are your classes inheriting from. To find the correct place you use the "go to definition" feature of Visual Studio.
e.g. for IQueryable.Count() the extension methods are implemented by System.Linq.Queryable static class as can be seen here → http://referencesource.microsoft.com/#System.Core/System/Linq/IQueryable.cs
So in order to encode the expression you need to encode a call to the extension method.
Much simpler way to generate expression trees from strings was shown quite early in a prototype published by Microsoft. Introductory article is available e.g. in Dynamic Expressions and Queries in LINQ
We use modified version of the original source of the automatic "string to linq" engine with success and it simplifies development a lot. By inspecting the source code of the System.Linq.Dynamic you can find exact way how to encode the expression. Link to the original source code available through NuGet is mentioned e.g. in Stack Overflow article Dynamic LINQ - Is There A .NET 4 Version?
I want to provide a set of filters for a user to pick from, and each filter will correspond to an Expression<Func<X, bool>>. So, I might want to take a dynamic list of available items ('Joe', 'Steve', 'Pete', etc), and create a collection of "hard-coded" filters based on those names, and let the user select which filter(s) he wants to use. My problem is that even when I try to "hard-code" my expression based on a string value from the dynamic list, the expression is still storing the value as, what looks to me, a property hanging off of an anonymous type (and I don't know how to serialize the anon. type). Sorry if this is confusing, I'm not quite sure how to articulate this.
Here's my sample code:
public class Foo
{
public string Name { get; set; }
}
static void Main(string[] args)
{
Foo[] source = new Foo[]
{
new Foo() { Name = "Steven" } ,
new Foo() { Name = "John" } ,
new Foo() { Name = "Pete" },
};
List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>();
foreach (Foo f in source)
{
Expression<Func<Foo, bool>> exp = x => x.Name == f.Name;
filterLst.Add(exp);
}
}
}
My problem is that when I look at when I look at the body of my expression, it reads as follows:
(x.Name = value(ConsoleApplication1.Program+<>c__DisplayClass3).value)
When what I really want is for the first one to read like this:
(x.Name = "Steven")
(if I change my code to this, instead, that's exactly what I get:
Expression<Func<Foo, bool>> exp = x => x.Name == "Steven";
)
I've tried forcing my value to a local string value before sticking it into the Expression, but it doesn't seem to help:
List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>();
foreach (Foo f in source)
{
string value = f.Name;
Expression<Func<Foo, bool>> exp = x => x.Name == value;
filterLst.Add(exp);
}
I don't understand why (or really even how) it's still looking at some anonymous type even once I'm using a local variable that is declared to a string. Is there a way to make this work as I want it to?
The anon-type is actually the compiler-generated type it is using to perform capture of the variables. With delegates you can hack around this by implementing the capture by hand, but not with lambda expressions compiled to expression-trees.
Two choices:
build the expression tree explicitely on code via Expression.Constant etc
learn how to handle the anon types
The latter isn't too bad actually; they are just MemberExpression typically, although I have some code kicking around that covers this in full detail. I can also provide examples of buildin the expression tree, but I'm not at a PC at the moment and it doesn't lend itself well to iPod typing...
From a brief read of the question I'd look at the first option more than the second.
Oh, and watch out; the first foreach code in the question looks susceptible to the notorious l-value capture issue ;)
Edit: I found a PC ;p
var param = Expression.Parameter(typeof(Foo), "x");
var body = Expression.Equal(
Expression.PropertyOrField(param, "Name"),
Expression.Constant(f.Name, typeof(string)));
var exp = Expression.Lambda<Func<Foo, bool>>(body, param);
filterLst.Add(exp);
Marc Gravell's answer is correct, and here's how you'd implement his first choice:
var filters =
from f in source
let param = Expression.Parameter(typeof(Foo),"x")
select Expression.Lambda<Func<Foo, bool>>(
Expression.Equal(
Expression.Property(param, "Name"),
Expression.Constant(f.Name)), param);
But this typically isn't necessary. Your second example of the for loop should work with all major LINQ providers. Is there a reason you need the expression to use constants?