I am trying to create a function that evaluates a DynamicLinq expression. While the expression itself is valid, the Parameter objects it has available to use may not always be what it needs.
I would like some method of checking if I have all the Parameters available that the expression needs before actually executing it. Currently the best option I have found is to wrap it in a try-catch and ignore the missing param exception.
var ValidLambdaExpression = "ObjectType.Attribute == \"testvalue\" && ObjectType2.Attribute == \"testvalue2\"";
var paramObjects = new List<System.Linq.Expressions.ParameterExpression>();
var p = System.Linq.Expressions.Expression.Parameter(typeof(ObjectType), "ObjectType");
paramObjects.Add(p);
var lam = System.Linq.Dynamic.DynamicExpression.ParseLambda(paramObjects.ToArray(), null, ValidLambdaExpression);
//var lambody = System.Linq.Dynamic.DynamicExpression.Parse(null, ValidLambdaExpression);
//var lam = System.Linq.Expressions.Expression.Lambda(lambody, paramObjects);
var result = DataValidation.ToBoolean(lam.Compile().DynamicInvoke(data));
In the block of code above, the ValidLambdaExpression variable may be referencing objects that do not exist in the data array. If that happens both the ParseLambda and Parse lines blow up. I have not found any method of parsing the lambda then checking for missing parameters, or even required parameters.
This block will blow up with the error:
ParseException -> Unknown identifier 'ObjectType2'
At the time of execution paramObjects gets dynamically built, it is not hard coded, so I do not know what objects will be put into it.
Does anyone have a better method "in terms of speed" of validating what parameters the Lambda needs before parsing it?
It seems as though no one had a solution for this problem. Here is the work-around I ended up coming up with.
At the time the Lambda expression was being built, I knew which objects were being put into it, even if I did not have that information by the time I needed to use the expression.
So I ended up prefixing the expression with a csv list of objects so I could gain access to them in the method that was using the expression.
The expression ended up looking like this:
ObjType1,ObjType2,ObjType3|ObjType1.Attribute == ObjType2.Attribute
Then I wrote a wrapper around the DynamicExpressionParser that was able to parse this string and make some intelligent decisions off of it before trying to invoke the expression.
Related
I have a problem with roslyn method DescendantNodes()..With this line
var blockNodes = root.DescendantNodes(n => n.IsKind(SyntaxKind.Block))
When I use lambda expression in this case in Debug mode it works..But when I build DLL and connect it to project as analyzer it dont work..It works only when I rewrite it to this:
var nodes = root.DescendantNodes();
var blockNodes = nodes.Where(n => n.IsKind(SyntaxKind.Block));
Where is the problem and how can i fix it ?
I don't know why debug mode works differently for you. However, I think you may be using the method DescendantNodes incorrectly.
The function that is passed to DescendantNodes is a predicate that determines if the algorithm walking down the syntax tree finding descendants continues on to a given node's children or not. If this function returns false, then no additional children down that syntax tree path are returned.
This is very different than using the LINQ Where method, which filters the set to only nodes that match the predicate.
For example, the first one might find all the nested pure blocks in a method body, but not find any blocks that are parts of other kinds of statements, since those will never be considered because other kinds of statements are not themselves blocks. However, using the second form (Where method), the function considers all nodes under the root, and thus finds all blocks.
I'm currently using LINQ to load a list of files into XDocuments, like so:
var fileNames = new List<string>(){ "C:\file.xml" };
var xDocs = fileNames.Select(XDocument.Load);
var xDocs2 = xDocs.ToList(); // Crashes here
If I deliberately 'lock' one of the files with a different process, the IOException is only thrown when I actually start to look at the XDocuments I've been generating, ie when ToList() is called.
Can anyone explain why this is, and how best to handle this error? I'd like to have access to the working XDocuments still, if possible.
Can anyone explain why this is
As many pointed out, this is because of the so called deferred execution of many LINQ methods. For instanse, the Enumerable.Select method documentation states
This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.
while the Enumerable.ToList documentation contains
The ToList<TSource>(IEnumerable<TSource>) method forces immediate query evaluation and returns a List that contains the query results. You can append this method to your query in order to obtain a cached copy of the query results.
So the XDocument.Load is really executed for each file name during the ToList call. I guess that covers the why part.
and how best to handle this error? I'd like to have access to the working XDocuments still, if possible.
I don't know what does "best" mean in this context, but if you want to ignore the errors and include the "working XDocuments", then you can use something like this
var xDocs = fileNames.Select(fileName =>
{
try { return XDocument.Load(fileName); }
catch { return null; }
});
and then either append .Where(doc => doc != null), or account for null documents when processing the list.
This is why the linq .Select is an IEnumerable and the elements are first called if you make your IEnumerable to an List. Then you go through all of your elements.
I am trying to use learn how to use FakeItEasy, and wanted to try using it with some data access code from an old project I have access to. While the basics of FIE seemed pretty easy, and I was able to get simple cases working, this one has me stumped.
The system used Entity Framework, and one of the data management classes handles Users, and I'm trying to figure out how to test just the basic GetUserByUserNumber function. I can use a fake IPersistenceManager<User> when instantiating the UserDataManager class, and then call the GetUserByUserNumber method, but the assertion to check that userPersistenceManager.ReadCustom was called always fails.
I've tried calling the Delete method on the fake userPersistenceManager, and the assertion for that works fine. I think it has something to do with the Linq Expression that the ReadCustom method takes as its first parameter. I just don't know how that should be handled. Any help with this would be appreciated!
This is the method in the UserDataManager that I'm trying to test:
public User GetUserByUserNumber(string userNumber, bool loadRelatedRecords = false)
{
if (string.IsNullOrWhiteSpace(userNumber))
{
throw MyAppExceptions.CreateMyAppFatalException(Constants.ExceptionKeys.Unexpected, new ArgumentNullException("userNumber"));
}
Logger.Write(string.Format("Executing GetUserByUserNumber with UserNumber {0}.", userNumber), LogCategory.General, TraceEventType.Verbose);
return _UserPersistenceManager.ReadCustom(mem => mem.UserNumber == userNumber, EntityConstants.EntityNames.UserDetail);
}
This is the IPersistenceManager method that I want to ensure is called:
TEntity ReadCustom(Expression<Func<TEntity, bool>> predicate, string includeEntityName);
This is my unit test:
[TestMethod]
public void GetUserByUserNumber_Calls_ReadCustom()
{
// Arrange
var userPersistenceManager = A.Fake<IPersistenceManager<User>>();
var dataManager = new UserDataManager(userPersistenceManager);
// Act
dataManager.GetUserByUserNumber("123456", false);
// Assert
A.CallTo(() => userPersistenceManager.ReadCustom(u => u.UserNumber == "123456", EntityConstants.EntityNames.UserDetail)).MustHaveHappened();
}
I think Tim Long's answer is essentially correct although my slant is not that this is a failing of mocking frameworks—it comes down to how easy it is (in general, not just when mocking) to determine whether two things are "the same".
The problem you have is that unless told otherwise, FakeItEasy uses .Equals to compare the arguments. Expressions don't compare well with .Equals, and so you'll get a mismatch.
One option is to explore Expression equality-checkers. There are a number of questions on StackOverflow about this already, such as How to check if two Expression<Func<T, bool>> are the same. If you can find a good way to determine the equality of the expressions, I think you could provide that method to FakeItEasy's argument matcher
(e.g. with A<Expression<Func<TEntity, bool>>.That.Matches(…)).
Alternatively, you can go Mr. Long's route and capture the argument and then interrogate it later. I suggested a similar approach just a bit ago when answering
How to fake an action<> with FakeItEasy.
In your case, you could capture the predicate and then verify its correctness by seeing how it reacts to various input objects - does it like ones with UserNumber "123456".
This seems to be an area of mocking frameworks that is very counter-intuitive and hard to use correctly. I generally shy away from doing argument matching and try to return or capture some sort of object that I can later make assertions against.
In your case, you are essentially comparing two expressions for equality. The 'look' different in the code even though they have the same syntax. I wonder, can you create those two expressions outside of the test context and see if they compare equal then?
Referring to this question:
Moq how to replace obsolete expression
I have the following:
[Test]
public void OnSearchRequest_ViewFiresEvent_EventIsHandled()
{
// Arrange
Mock<IViewUsers> view = new Mock<IViewUsers>();
Users users = new Users(view.Object);
// Act
view.Raise(v => v.SearchForUsers += null, this, new SearchEventArgs());
// Assert
view.VerifySet(v=> v.SearchResult = It.IsAny<List<IUser>>());
}
originally I had:
// Assert
view.VerifySet(v => v.SearchResult);
But was getting the warning:
'Moq.MockExtensions.VerifySet(Moq.Mock,
System.Linq.Expressions.Expression>)' is
obsolete: 'Replaced by VerifySet(Action)'
So I found the question referenced above, and changed it to match, but now I'm STILL getting that warning, and on top of that, a hard error on "v.SearchResult" within the call to VerifySet :
An expression tree may not contain an assignment operator.
I can't see that I'm formatting this improperly - so why isn't it recognizing this as an action as the other question implies it should?
I found something relatively close to what you are asking about. Moq how to replace obsolete expression I don't know if this helps because I only ever used mock.Setup and mock.Verify.
Also as mentioned before try using lambda expressions within your It.IsAny to pinpoint smaller things this way . If a verify fails you know exactly where it failed. Especially if you are expecting a value at a certain position for example.
I don't know if it helps, but I've had problems in the past using It.IsAny<> with lists. Could you try something like It.Is<List<IUser>>(l => l != null)?
Is it possible to pass a lambda expression to a secondary AppDomain as a stream of IL bytes and then assemble it back there using DynamicMethod so it can be called?
I'm not too sure this is the right way to go in the first place, so here's the (detailed) reason I ask this question...
In my applications, there are a lot of cases when I need to load a couple of assemblies for reflection, so I can determine what to do with them next. The problem part is I need to be able to unload the assemblies after I'm finished reflecting over them. This means I need to load them using another AppDomain.
Now, most of my cases are sort of similar, except not quite. For example, sometimes I need to return a simple confirmation, other times I need to serialize a resource stream from the assembly, and again other times I need to make a callback or two.
So I end up writing the same semi-complicated temporary AppDomain creation code over and over again and implementing custom MarshalByRefObject proxies to communicate between the new domain and the original one.
As this is not really acceptable anymore, I decided to code me an AssemblyReflector class that could be used this way:
using (var reflector = new AssemblyReflector(#"C:\MyAssembly.dll"))
{
bool isMyAssembly = reflector.Execute(assembly =>
{
return assembly.GetType("MyAssembly.MyType") != null;
});
}
AssemblyReflector would automize the AppDomain unloading by virtue of IDisposable, and allow me to execute a Func<Assembly,object>-type lambda holding the reflection code in another AppDomain transparently.
The problem is, lambdas cannot be passed to other domains so simply. So after searching around, I found what looks like a way to do just that: pass the lambda to the new AppDomain as an IL stream - and that brings me to the original question.
Here's what I tried, but didn't work (the problem was BadImageFormatException being thrown when trying to call the new delegate):
public delegate object AssemblyReflectorDelegate(Assembly reflectedAssembly);
public class AssemblyReflector : IDisposable
{
private AppDomain _domain;
private string _assemblyFile;
public AssemblyReflector(string fileName) { ... }
public void Dispose() { ... }
public object Execute(AssemblyReflectorDelegate reflector)
{
var body = reflector.Method.GetMethodBody();
_domain.SetData("IL", body.GetILAsByteArray());
_domain.SetData("MaxStackSize", body.MaxStackSize);
_domain.SetData("FileName", _assemblyFile);
_domain.DoCallBack(() =>
{
var il = (byte[])AppDomain.CurrentDomain.GetData("IL");
var stack = (int)AppDomain.CurrentDomain.GetData("MaxStackSize");
var fileName = (string)AppDomain.CurrentDomain.GetData("FileName");
var args = Assembly.ReflectionOnlyLoadFrom(fileName);
var pars = new Type[] { typeof(Assembly) };
var dm = new DynamicMethod("", typeof(object), pars,
typeof(string).Module);
dm.GetDynamicILInfo().SetCode(il, stack);
var clone = (AssemblyReflectorDelegate)dm.CreateDelegate(
typeof(AssemblyReflectorDelegate));
var result = clone(args); // <-- BadImageFormatException thrown.
AppDomain.CurrentDomain.SetData("Result", result);
});
// Result obviously needs to be serializable for this to work.
return _domain.GetData("Result");
}
}
Am I even close (what's missing?), or is this a pointless excercise all in all?
NOTE: I realize that if this worked, I'd still have to be carefull about what I put into lambda in regard to references. That's not a problem, though.
UPDATE: I managed to get a little further. It seems that simply calling SetCode(...) is not nearly enough to reconstruct the method. Here's what's needed:
// Build a method signature. Since we know which delegate this is, this simply
// means adding its argument types together.
var builder = SignatureHelper.GetLocalVarSigHelper();
builder.AddArgument(typeof(Assembly), false);
var signature = builder.GetSignature();
// This is the tricky part... See explanation below.
di.SetCode(ILTokenResolver.Resolve(il, di, module), stack);
dm.InitLocals = initLocals; // Value gotten from original method's MethodInfo.
di.SetLocalSignature(signature);
The trick is as follows. Original IL contains certain metadata tokens which are valid only in the context of the original method. I needed to parse the IL and replace those tokens with ones that are valid in the new context. I did this by using a special class, ILTokenResolver, which I adapted from these two sources: Drew Wilson and Haibo Luo.
There is still a small problem with this - the new IL doesn't seem to be exactly valid. Depending on the exact contents of the lambda, it may or may not throw an InvalidProgramException at runtime.
As a simple example, this works:
reflector.Execute(a => { return 5; });
while this doesn't:
reflector.Execute(a => { int a = 5; return a; });
There are also more complex examples that are either working or not, depending on some yet-to-be-determined difference. It could be I missed some small but important detail. But I'm reasonably confident I'll find it after a more detailed comparison of the ildasm outputs. I'll post my findings here, when I do.
EDIT: Oh, man. I completely forgot this question was still open. But as it probably became obvious in itself, I gave up on solving this. I'm not happy about it, that's for sure. It's really a shame, but I guess I'll wait for better support from the framework and/or CLR before I attempt this again. There're just to many hacks one has to do to make this work, and even then it's not reliable. Apologies to everyone interested.
I didn't get exactly what is the problem you are trying to solve, but I made a component in the past that may solve it.
Basically, its purpose was to generate a Lambda Expression from a string. It uses a separate AppDomain to run the CodeDOM compiler. The IL of a compiled method is serialized to the original AppDomain, and then rebuild to a delegate with DynamicMethod. Then, the delegate is called and an lambda expression is returned.
I posted a full explanation of it on my blog. Naturally, it's open source. So, if you get to use it, please send me any feedback you think is reasonable.
Probably not, because a lambda is more than just an expression in source code. lambda expressions also create closures which capture/hoist variables into their own hidden classes. The program is modified by the compiler so everywhere you use those variables you're actually talking to the class. So you'd have to not only pass the code for the lambda, but also any changes to closure variables over time.