Please help this Linq newbie!
I'm creating a list inside my class under test, and I would like to use Moq to check the results.
I can easily put together a Predicate which checks the results of the list. How do I then make that Predicate into an Expression?
var myList = new List<int> {1, 2, 3};
Predicate<List<int>> myPredicate = (list) =>
{
return list.Count == 3; // amongst other stuff
};
// ... do my stuff
myMock.Verify(m => m.DidStuffWith(It.Is<List<int>>( ??? )));
??? needs to be an Expression<Predicate<List<int>>>
if you can get your head round that many generics. I've found a开发者_开发知识库nswers which do this the other way round and compile an Expression into a Predicate. They're not helping me understand Linq any better, though.
EDIT: I've got it working with methods; with expressions; I would just like to know if there's any way to do it with a lambda with a body - and if not, why not?
Change:
Predicate<List<int>> myPredicate = (list) => list.Count == 3;
To:
Expression<Predicate<List<int>>> myPredicate = (list) => list.Count == 3;
The compiler does the magic for you. With some caveats1, any lambda dealing only with expressions (no blocks) can be converted into an expression tree by wrapping the delegate type (in this case Predicate<List<int>>
) with Expression<>
. As you noted, you could then invert it yet again by calling myPredicate.Compile()
.
1 For example, async lambdas (i.e. async () => await Task.Delay(1);
) cannot be converted to an expression tree.
Update: You simply cannot use the compiler to arrive at the expression tree you want if it includes statements. You'll have to build up the expression tree yourself (a lot more work) using the static methods in Expression
. (Expression.Block
, Expression.IfThen
, etc.)
Kirk Woll's answer directly addresses your question, but consider the fact that you can use the Callback
method on a Setup
of a void
method to handle the parameters which were passed in on invocation. This makes more sense to me since you're already having to build a method to validate the list anyway; it also gives you a local copy of the list.
//what is this list used for?
var myList = new List<int> {1, 2, 3};
List<int> listWithWhichStuffWasDone = null;
//other setup
myMock.Setup(m => m.DoStuffWith(It.IsAny<List<int>>()).
Callback<List<int>>(l => listWithWhichStufFWasDone = l);
objectUnderTest.MethodUnderTest();
myMock.Verify(m => m.DoStuffWith(It.IsAny<List<int>>()));
Validate(listWithWhichStuffWasDone);
精彩评论