I'm trying to create an extension method for Moq where I can send in an expression to be used in an async return function. However this question is not really Moq specific. Here's what I have so far:
public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult, T>(this IReturns<TMock, Task<TResult>> setup, Func<T, TResult> valueFunc) where TMock : class
{
return setup.Returns(Task.FromResult(valueFunc.Invoke(default(T))));
}
This is how I'm hoping to use it.
repo.Setup(x => x.FindAsync(It.IsAny<Expression<Func<T, bool>>>())).ReturnsAsync((Expression<Func<T, bool>> e) => context.GetSet<T>().FirstOrDefault(e));
Now I don't really know how all of this works and the thing I can't figure out is how to I get the expression passed on into the ReturnsAsync function so I can use it as the argument instead of the default(T) that I put there as a placeholder.
As expected the "e" variable here becomes null.
This method will do what you want:
public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult, T>(
this IReturns<TMock, Task<TResult>> setup,
Func<Expression<Func<TResult, T>>, TResult> valueFunc)
where TMock : class
{
return setup.Returns<Expression<Func<TResult, T>>>(
e => Task.FromResult(valueFunc(e)));
}
Then use it like so:
repo.Setup(x => x.FindAsync(It.IsAny<Expression<Func<T, bool>>>()))
.ReturnsAsync<IRepository, int, bool>(e => context.GetSet<T>().FirstOrDefault(e));
Essentially, this version of ReturnsAsync takes a function that expects a predicate function (which is e) and returns a T. This allows you to then execute the predicate against your test data set (context.GetSet<T>.FirstOrDefault). Also, I used the overload of Returns that accepts a type parameter; this is used to forward the arguments from the Setup call to the function specified as the Returns argument.
Your version's signature only specified the predicate, so you had no way to execute it against your test data. You also had the T and TResult type parameters backwards in the valueFunc parameter's type.
Related
I am trying to make an extension method more generic to avoid redundancy (Here is an example of some real code, the code below is just to demonstrate the issue - I had the idea to make the method available for IQueryable<T> as well).
The following works fine:
public static class Extensions
{
public static IEnumerable<T> MySelect1<T, V>(this IEnumerable<T> query, Func<T, V> f)
{
// do something, then return IEnumerable<T>
var result=query.AsEnumerable<T>();
return result;
}
public static IQueryable<T> MySelect1<T, V>(this IQueryable<T> query, Func<T, V> f)
{
// do something, then return IQueryable<T>
var result = query.AsQueryable<T>();
return result;
}
}
I can use it in LinqPad like (when connected with the Northwind sample database):
var myQuery=(from x in Customers select x);
myQuery.AsEnumerable().MySelect1(d => d.CustomerID).Dump();
myQuery.AsQueryable().MySelect1(d => d.CustomerID).Dump();
Now I wanted to get rid of the duplicate implementation of MySelect1, so I refactored it as:
public static class Extensions
{
public static E MySelect2<E, T, V>(this E query, Func<T, V> f)
where E : System.Linq.IQueryable<T>, System.Collections.Generic.IEnumerable<T>
{
return (E)query.Select(f);
}
}
This compiles too, but I cannot use MySelect2 the same way as I did above, consider the following:
// CS0411 The type arguments for method 'Extensions.MySelect2<E, T, V>(E, Func<T, V>)'
// cannot be inferred from the usage. Try specifying the type arguments explicitly.
myQuery.AsEnumerable().MySelect2(d => d.CustomerID).Dump();
myQuery.AsQueryable().MySelect2(d => d.CustomerID).Dump();
Ok, doing what the error asks for works for this code line:
myQuery.AsQueryable()
.MySelect2<IQueryable<Customers>, Customers, String>(d => d.CustomerID).Dump();
but not for that one:
myQuery.AsEnumerable<Customers>()
.MySelect2<IEnumerable<Customers>, Customers, String>(d => d.CustomerID).Dump();
Here, I am getting
CS0311 The type 'System.Collections.Generic.IEnumerable<LINQPad.User.Customers>' cannot be used as type parameter 'E' in the generic type or method 'Extensions.MySelect2<E, T, V>(E, Func<T, V>)'. There is no implicit reference conversion from 'System.Collections.Generic.IEnumerable<LINQPad.User.Customers>' to 'System.Linq.IQueryable<LINQPad.User.Customers>'.
Why? And how can it be fixed? Please help.
Why?
For exactly the reason stated in the error message: you're trying to use IEnumerable<Customers> as the type argument for E, but E has this constraint:
where E : System.Linq.IQueryable<T>
And how can it be fixed?
It can't, assuming I understand what you're trying to achieve.
There's a fundamental problem with the "simplification" you're trying to achieve: you don't actually have full duplication in your original MySelect1 methods. The first calls AsEnumerable() and the second calls AsQueryable(). You're trying to replace those with a cast, and that's just not going to work.
There's a further problem, even with your original methods: you're accepting Func<T, V> f as a parameter for your queryable-based method, which means any time you call Select or similar and passing in f, you'll be calling Enumerable.Select instead of Queryable.Select. To really use IQueryable<> properly, you should accept Expression<Func<T, V>> f instead. At that point, you won't need to call AsQueryable anyway.
Your two methods "should" take radically different paths based on whether you're using LINQ to Objects or a different LINQ provider (e.g. LINQ to SQL), and that can't be hidden as a pure implementation detail without significant changes that would probably make it less useful than you want anyway.
I'm implementing a fluent argument assertion library where the focus is in strong type checking on compile time. Intellisense should only show methods and extensions available for the asserted type.
I'm having problems resolving proper type arguments when creating an extension for IEnumerable.
Idea in the library is that you can call ThrowIf (or ThrowIfNot) on any type which will return you an assertion instance of type IAssertion:
public static IAssertion<T> ThrowIf<T>(this T t)
{
return new IfAssertion<T>(t);
}
Now I want to check against IEnumerable if it contains a specific item. There will be two overloads where one takes the object of type T as a parameter and the other takes a function where to do the evaluation:
public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, T2 item)
where T1 : IEnumerable<T2>
{
// assertion logic
return assertion.Value;
}
public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, Func<T2, bool> func)
where T1 : IEnumerable<T2>
{
// assertion logic
return assertion.Value;
}
Everything goes fine when using the overload taking an instance of the actual type. But the latter one with the function compiler cannot infer the type arguments properly unless cast is made:
var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // does not compile
Is there any way I could make the compiler happy without doing the cast for the function parameter?
More implementation details can be found from here:
https://bitbucket.org/mikalkai/argument-assertions/overview
Disclaimer: This answer is only valid if IAssertion can be made covariant.
Assuming that IAssertion is covariant, you don't necessarily need two generic type parameters T1 and T2 for the Contains methods. Instead, you specify IEnumerable in your interface directly and use only one generic type parameter like this:
public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, T item)
{
// assertion logic
return assertion.Value;
}
public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, Func<T, bool> func)
{
// assertion logic
return assertion.Value;
}
Then you can use the contains method like this:
var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // compiles now too
I'm trying to pass an expression that describes a method but I want the argument to be strongly typed and I don't want to have to know the method signature or pass the arguments in the expression, something like this:
GetMethod<MyClass>(c => c.DoSomething);
Where DoSomething could have a method signature like this... string DoSomething(int id, int count)
I know I can do something like this:
MemberInfo GetMethod<T>(Expression<Func<T, Delegate>> expression);
//implementation
GetMethod<MyClass>(c => new Func<int, int, string>(c.DoSomething))
But frankly, this is quite ugly.
Is this possible?
Just have an overload for each possible Action/Func. It won't cover all possibilities (have an extra overload that you've shown there to cover all edge cases) but it'll handle most of them.
The body of each of the action/func overloads can just call the overload that you've shown above for the actual implementation.
public MemberInfo GetMethod<T1, T2>(Expression<Func<T1, Func<T2>>> expression)
{
return GetMethodImpl(expression);
}
public MemberInfo GetMethod<T1, T2, T3>(Expression<Func<T1, Func<T2, T3>>> expression)
{
return GetMethodImpl(expression);
}
public MemberInfo GetMethod<T1, T2>(Expression<Func<T1, Action<T2>>> expression)
{
return GetMethodImpl(expression);
}
//...
GetMethodImpl can then be implemented like so:
private MemberInfo GetMethodImpl<T1, T2>(Expression<Func<T1, T2>> expression)
{
}
That will be able to be just a slight modification of your existing GetMethod implementation. T2 will be your delegate; you may need to cast it to Delegate, depending on how you use it.
Func<> is very convenient in .NET. Is there a way i can specify the param type and have the result value as void? I'd like to pass void Write(string) as a parameter.
Action<T> - "Encapsulates a method that takes a single parameter and does not return a value"
I believe you're looking for the Action<T> family of delegate types.
It's not perfect, but sometimes when I want to fake this behavior against an existing function (and I'd rather not re-implement it as Action<TResult>) I'll just return null and throw the value away.
Func<T, TResult> myFunc = (inVar) =>
{
// do work...
return null as object;
};
How can I supply a func to a method, so I could write something like:
MethodTest(a => a.IsAltTagAvailable);
Where the signature of this method takes a func which returns an object (say HtmlImage) when the condition is met (basically just a predicate).
Edit: I need to pass the type I will be working on as T (Parameter). I forgot to do this, how clumsy!
Thanks
A predicate tends to return bool, not an object. What are you going to return when the condition isn't met? Given your example, you don't really mean the function returns an object - you mean it takes an object and returns a bool.
Note that if you're going to have a parameter in the lambda expression, you'll need to use a delegate which takes parameters too.
We really need more information before giving a definitive answer, but you might want something like:
void MethodTest(Func<HtmlImage, bool> predicate)
or
void MethodTest(Predicate<HtmlImage> predicate)
(Personally I like the descriptive nature of using a named delegate, but others prefer to use Func/Action for almost everything.)
That's assuming that the type of input is fixed. If not, you might want to make it a generic method:
void MethodTest<T>(Predicate<T> predicate)
void MethodTest(Func<HtmlImage> func) {
}
void MethodTest(Func<HtmlImage, object> func)
{
}
HtmlImage is the argument of the function (x), object the return value, you could take the concrete type if you want to specify it.
void MethodTest(Func<HtmlImage, bool> func)
Which is a predicate:
void MethodTest(Predicate<HtmlImage> func)
To make it fully generic, replace HtmlImage with a generic argument:
void MethodTest<T>(Predicate<T> func)
public void MethodTest(Func<HtmlImage> delegate)
{
//do what you want
}
OR:
public delegate HtmlImageTagHandler(HtmlImage image);
public HtmlImage MethodTest(HtmlImageTagHandler handler, HtmlImage image)
{
return handler(image) == true ? image : null;
}
use:
MethodTest(a => a.IsAltTagAvailable, a);