I'm building a C# expression-to-Javascript converter, along the lines of Linq-to-SQL, but I'm running into problems with compiler generated expression trees.
The particular problem I'm having is dealing with MemberExpression values which were compiler generated, but which DO NOT have the CompilerGeneratedAttribute specified on their types.
Here's a cut-down version of what I've been trying:
void ProcessMemberExpression(MemberExpression memberX) {
var expression = memberX.Expression;
var expressionType = expression.Type;
var customAttributes = expressionType.GetCustomAttributes(true);
var expressionTypeIsCompilerGenerated = customAttributes.Any(x => x is CompilerGeneratedAttribute);
if (expressionTypeIsCompilerGenerated) {
var memberExpressionValue = Expression.Lambda(memberX).Compile().DynamicInvoke();
... do stuff ...
}
else {
... do other stuff ...
}
}
Now, I have a Visual Studio debugging session open and I find this (running in the Immediate Window):
expressionType.Name
"<>c__DisplayClass64"
expressionType.GetCustomAttributes(true)
{object[0]}
expressionType.GetCustomAttributes(true).Length
0
So what I have here is an obviously compiler generated class with no custom attributes and hence no CompilerGeneratedAttribute! Therefore, my code will do other stuff, when I intend it to just do stuff.
If anyone could help me out here, I'd be very grateful. If at all possible, I'd really rather not do anything sordid like matching the expressionType.Name against something like <>.*__DisplayClass.
Based on Jon Skeet's answer here, it sounds like checking for angle brackets will work.
Where/what is the private variable in auto-implemented property?
Related
I'm using Roslyn to generate code for a tool I'm building. I'm using the SyntaxGenerator (as opposed to SyntaxFactory) as I'd prefer to not have to write implementations for both C# and VB.NET.
According to the reference source, the AssignmentStatement deliberately adds parentheses to the right side node. E.g.
Key = (key)
Whereas what I'm looking for is without parentheses:
Key = key
Example
This is a very basic, very watered down example which should reproduce this behaviour.
public void Example()
{
using (var workspace = new AdhocWorkspace())
{
var generator = SyntaxGenerator.GetGenerator(workspace, LanguageNames.CSharp);
var statement = generator.AssignmentStatement(generator.IdentifierName("Key"), generator.IdentifierName("key"));
var result = statement.NormalizeWhitespace().ToFullString();
}
}
I've searched extensively both here on SO as well as on Github, Roslyn Reference Source and various blogs and examples* but can't seem to find an elegant way to remove these redundant parentheses.
Although this is still legal syntax and will compile, it's really annoying.
Any ideas? Am I doing something wrong? Tips? Hopeless case?
*This example generates a constructor with redundant parentheses in the assignments as well.
I have a method
public static class PropertyLensMixins
{
public static ILens<Source> PropertyLens<O,Source>
( this O o
, Expression<Func<O, Source>> selector
)
where O: class, INotifyPropertyChanged
where Source: class, Immutable
{
return new PropertyLens<O, Source>(o, selector);
}
}
and the idea is to use it this way
this.PropertyLens(p=>p.MyProp)
however it is an error to create a nested expression even though the compiler will accept it
this.PropertyLens(p=>p.MyProp.NestProp)
now I can catch this at runtime by parsing the expression tree. For example
var names = ReactiveUI.Reflection.ExpressionToPropertyNames(selector).ToList();
if (names.Count > 1)
throw new ArgumentException("Selector may only be depth 1", "selector");
I was wondering however, is there any clever way to detect this at compile time? I doubt it because the compiler is happy with the type signature but I thought I might ask anyway.
I have also tried a Resharper pattern to match it as an error
$id0$.PropertyLens($id1$=>$id1$.$id2$.$id3$)
with all placeholders being identifiers but Resharper can't seem to match it.
There is no way to make the compiler reject such code.
One possible alternative would be to create a custom diagnostic using Roslyn. That way, all such errors will be marked by VS. Though it might be too much work for something like this.
I'm creating an expression tree manually like this
var innerAddition = Expression.Add(Expression.Constant(5), Expression.Constant(9));
var mult = Expression.Multiply(innerAddition, Expression.Constant(2));
var top = Expression.Add(Expression.Constant(3), mult);
When I look at DebugView in debug mode, I see 3 + (5 + 9) * 2, which is what I would like to output from my program. I understand this is using the expression tree visualizer. Is there a way to use this from my code?
Thanks!
Here is a simple extension method to get the internal property's value using reflection.
public static string GetDebugView(this Expression exp)
{
if (exp == null)
return null;
var propertyInfo = typeof(Expression).GetProperty("DebugView", BindingFlags.Instance | BindingFlags.NonPublic);
return propertyInfo.GetValue(exp) as string;
}
The classes that implement the debug view features are intentionally internal so that you cannot access them without reflection. Although this seems unfair, the purpose of debugging is debugging and it is not intended as a supported API and therefore could change at any time, perhaps to improve debugging! Using the supported public APIs will ensure compatibility with future versions.
Here is another StackOverflow question using the public APIs:
Print out Linq Expression Tree Hierarchy
While the classes are internal, the source code is public :-)
http://referencesource.microsoft.com/#System.Core/Microsoft/Scripting/Ast/DebugViewWriter.cs,05c213f459ccd9cb
Obviously you have to fix up a few things but its not too difficult to get it to work.
http://referencesource.microsoft.com/#System.Core/Microsoft/Scripting/Ast/ExpressionStringBuilder.cs gives the mouse-over text you see for an expression in Visual Studio when debugging.
Depending on your needs either that or DebugViewWriter.cs as Andrew Jackson mentioned should cover things.
Given the following statement lambda example:
var fMyAction = new Action(() =>
{
x += 2;
something = what + ever;
});
What are possible ways to get the body of that lambda and dump it to string? (Something that will ultimately allow to write an extension method for Action class of this kind: fMyAction.Dump() which will return "x += 2; something = what + ever;").
Thanks
It's not possible in that form. Your lamda gets compiled to byte-code. While in theory it's possible to decompile the byte-code, just like reflector does, it's difficult, error prone and doesn't give you the exact code you compiled, but just code that's equivalent.
If you use an Expression<Action> instead of just Action you get the expression tree describing the lamda. And converting an expression tree to a string is possible(and there are existing libraries which do it).
But that's not possible in your example because it's a multi statement lamda. And only simple lamdas can be automatically converted to an expression tree.
Read through the tutorial here,
http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx
Pay close attention to the visitor pattern he uses to walk a given expression tree. You should be able to alter it to fit your needs easy enough.
I have a method that alters an "Account" object based on the action delegate passed into it:
public static void AlterAccount(string AccountID, Action<Account> AccountAction) {
Account someAccount = accountRepository.GetAccount(AccountID);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
This works as intended...
AlterAccount("Account1234", a => a.Enabled = false);
...but now what I'd like to try and do is have a method like this:
public static void AlterAccount(string AccountID, string AccountActionText) {
Account someAccount = accountRepository.GetAccount(AccountID);
Action<Account> AccountAction = MagicLibrary.ConvertMagically<Action<Account>>(AccountActionText);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
It can then be used like:
AlterAccount("Account1234", "a => a.Enabled = false");
to disable account "Account1234".
I've had a look at the linq dynamic query library, which seems to do more or less what I want but for Func type delegates, and my knowledge of Expression trees etc isn't quite good enough to work out how to achieve what I want.
Is there an easy way to do what I want, or do I need to learn expressions properly and write a load of code?
(The reason I want to do this is to allow an easy way of bulk updating account objects from a powershell script where the user can specify a lambda expression to perform the changes.)
The Dynamic LINQ library is a fine choice, as it'll generate expressions you can compile to code in a lightweight fashion.
The example you provided actually produces a boolean -- so you should be able to ask for a Func and it might sort it out.
Edit: This of course is wrong, as Expressions don't have assignment in them at all.
So, another potential way is to take two lambdas. One to find the property you want, one to provide a value:
(a => a.AccountId), (a => true)
Then use reflection to set the property referenced in the first lambda with the result of the second one. Hackish, but it's still probably lightweight compared to invoking the C# compiler.
This way you don't have to do much codegen yourself - the expressions you get will contain most everything you need.
You may try this: Dynamic Lambda Expressions Using An Isolated AppDomain
It compiles a lambda expression using CodeDOM compiler. In order to dispose the in-memory assembly that gets created, the compiler runs on an isolated AppDomain. For the passing the expression through the domain boundary, it has to be serialized. Alas, Expression<> is not Serializable. So, a trick has to be used. All the details are explained in the post.
I'm the author of that component, by the way. I would like very much to hear your feedback from it.
There is no general way to parse a string into a lambda expression without a full compilation, because lambda expressions can reference things that are defined outside the lambda expression. I know of no library that handles the specific case you want. There's a long discussion of this on a thread on a C# discussion group.
The easiest way to get what you want is to compile a method at runtime. You can write a function that takes in the string "a.Enabled = true; return a;" and sticks that in the middle of a function that takes an Account as a parameter. I would use this library as a starting point, but you can also use the function mentioned on another thread.
That's easy:
Use CodeDom to generate the module containing the "surrounding class" you'll use to build the expression; this class must implement the interface known to your application
Use CodeSnippedExpression to inject the expression into its member.
Use Activator type to create the instance of this class in runtime.
Basically, you need to build the following class with CodeDom:
using System;
using MyNamespace1;
using ...
using MyNamespace[N];
namespace MyNamespace.GeneratedTypes
{
public class ExpressionContainer[M] : IHasAccountAction
{
public Action<Account> AccountAction {
get {
return [CodeSnippedExpression must be used here];
}
}
}
}
Assuming that IHasAccountAction is:
public IHasAccountAction {
public Action<Account> AccountAction { get; }
}
If this is done, you can get the expression compiled from string with ease. If you need its expression tree representation, use Expression<Action<Account>> instead of Action<Account> in generated type.