How to find an overloaded method by reflection - c#

This is a question associated with another question I asked before. I have an overloaded method:
public void Add<T>(SomeType<T> some) { }
public void Add<T>(AnotherType<T> another) { }
How can I find each method by reflection? e.g. How can I get the Add<T>(SomeType<T> some) method by reflection? Can you help me please? Thanks in advance.

The trick here is describing that you want the parameter to be SomeType<T>, where T is the generic type of the Add method.
Other than that, it's just about using standard reflection, like CastroXXL suggested in his answer.
Here's how I did it:
var theMethodISeek = typeof(MyClass).GetMethods()
.Where(m => m.Name == "Add" && m.IsGenericMethodDefinition)
.Where(m =>
{
// the generic T type
var typeT = m.GetGenericArguments()[0];
// SomeType<T>
var someTypeOfT =
typeof(SomeType<>).MakeGenericType(new[] { typeT });
return m.GetParameters().First().ParameterType == someTypeOfT;
})
.First();

Look into the MethodInfo Members: http://msdn.microsoft.com/en-US/library/system.reflection.methodinfo_members(v=vs.80).aspx
There are helper properties for IsGenericMethodDefinition and GetParameters. Both could help you figure out what function is what.

Related

How to match method with a complex generic parameter using reflection?

I am trying to call a EntityFramework method using reflection.
The signature of the method is
DbCollectionEntry<TEntity, TElement> Collection<TElement>
(Expression <Func<TEntity, ICollection <TElement>>> navigationProperty) where TElement : class
where TEntity is a type parameter of the class. How can construct a type which which will equal Expression <Func<TEntity, ICollection <TElement>>> so I can find the right overload of the method? I tried typeof(Expression<>).MakeGenericType(new[] { typeof(Func<,>) }); which displays the same in the debugger but doesn't match by equality. Once I have the method how do I call it? I managed to find the method by excluding the one with a string parameter but I still want find out how to match the method properly. I tried invoking the method using method.MakeGenericMethod(typeof(MyType)).Invoke(context.Entry(t), new[] { lambda }); but I get the exception "Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true." Here's what I have so far
var collectionMethod = typeof(DbEntityEntry<>)
.GetMethods()
.Where(m => m.Name == "Collection")
.Select(m => new { Method = m, Params = m.GetParameters(), Args = m.GetGenericArguments() })
.Where(x => x.Args.Length == 1 && x.Params[0].ParameterType != typeof(string))
.Select(x => x.Method)
.First();
var lambda = Expression.Lambda<Func<Trade, ICollection<TradeLeg>>>(prop, param);
// this fails
var o = collectionMethod.MakeGenericMethod(typeof(TradeLeg))
.Invoke(context.Entry(t), new[] { lambda });
var collectionMethod = typeof(DbEntityEntry<>)
This line condemns you to a failure, because the method will be looked for on the generic definition, not on the constructed type you use. The method must be identified on the concrete type, not on the definition, in order to call it. Based on your code, I assume the correct expression is typeof(DbEntityEntry<Trade>).

Can I use Strongly type parameters based on properties from Object

I have a list of objects.
I have a single item with same type as the list.
I would like to create a generic extension method (called Find) to find an item from the list based on the single obj as well as an arbitrary list of its strongly typed properties.
Here is how I would like to call the method:
var obj = new SomeObject() { ... } ;
var list = new List<SomeObject>() { ... };
// Find similar objects
list.Find(obj, x => x.Id,y => y.Description);
Is this arrangement possible?
FirstOrDefault would work as in the comment below. However, I am looking for a way to use the pattern in different scenarios that might not be a simple lookup.
You can do this
public static T Find<T>(this IEnumerable<T> source, params Func<T,bool>[] condition)
{
return source.FirstOrDefault(o => condition.All(f => f(o))); // use All for && or use Any for ||
}
And to use it
var item = list.Find(x=> x.Id == obj.Id,x=> x.Description == obj.Description);
You can use Object if you want to make this work more generally by casting properties to object. but this will be a bit slower by the way and you must note that the Equals method for custom types must be overriden in order to make it work.
public static T Find<T>(this IEnumerable<T> source, T obj, params Func<T, object>[] condition)
{
return source.FirstOrDefault(o => condition.All(f => f(o).Equals(f(obj))));
}
Then you can call it exactly like this.
var item = list.Find(obj, x => x.Id,y => y.Description);
You can use Where if you want to return all similar items. by just changing FirstOrDefault into Where and the return type of method into IEnumerable<T>
It doesn't seem to me like you're saving a lot of time/effort versus just using a normal Where clause that filters on whichever properties you're after.
var findResults = list.Where(x => x.Id == obj.Id || x.Description == obj.Description);
Maybe you should consider proceeding like this:
var myResult = from currentObject in mylist
where currentObject == mySingleObject // change it by your matching criterias linked by && or || (as in if ...)
// NB: you can also override the == operator in your object definition
// but as mentionned below, it won't work for generic types
select currentObject;

Cannot resolve method between Enumerable and Queryable candidates

I have this method in a class called Invoice:
public static Expression<Func<Invoice, bool>> IsAllocated()
{
return i => i.TotalAmountDue == i.GetAllocationsTotal();
}
I have a list like this:
IQueryable<Invoice> invoices
And I need to filter it like that (it's Linq to Entity):
var filteredInvoices = invoices.Where(i => Invoice.IsAllocated());
In this line I'm getting two errors:
Cannot resolve method ... candidates are .... one in Enumerable and the other on in Queryable.
And also:
Cannot convert expression type Expression<Func<Invoice,bool>> to
return type 'bool'
I've tried a lot of things I've found in SO with no luck. Can someone say me what is missing here or at least, which one of the two errors is at the root of the problem?
Your method returns an appropriate expression tree already - you just need to call it, not call it in a lambda expression:
var filteredInvoices = invoices.Where(Invoice.IsAllocated());
Expression are representation and not delegate by themselves. You should create a delegate out of it first
static Expression<Func<Invoice, bool>> IsAllocatedExpr()
{
return i => i.TotalAmountDue == i.GetAllocationsTotal();
}
public static Func<Invoice, bool> IsAllocated = IsAllocatedExpr().Compile();
and then
var filteredInvoices = invoices.Where(i => Invoice.IsAllocated(i));

Rhino Mocks, assert that a MockRepository was not used (methods)?

Is there a way of asserting that no methods were called in MockRepository?
Say I have:
var repo = MockRepository.GenerateStub<RealRepo>();
I know I can do:
repo.AssertWasNotCalled(...);
But is there a way of checking that it was not used? Instead of doing all the methods everytime i want to check if a repo was not used?
I have cases where I want to just check that I don't use this repo.
Use StrictMock instead of stub:
var repo = MockRepository.GenerateStrictMock<RealRepo>();
It will throw exception if you will try to call any member which do not have setup.
BTW same is true for Moq:
var repoMock = new Mock<RealRepo>(MockBehavior.Strict);
You can try adding your own extension to Rhino Mocks. Something like this:
public static void AssertNothingWasCalled<T>(this T mock)
{
var methodsToVerify = typeof (T)
.GetMethods()
.Where(m => !m.IsSpecialName);
foreach (var method in methodsToVerify)
{
var arguments = BuildArguments(method);
var action = new Action<T>(x => method.Invoke(x, arguments));
mock.AssertWasNotCalled(action, y => y.IgnoreArguments());
}
}
private static object[] BuildArguments(MethodInfo methodInfo)
{
return methodInfo
.GetParameters()
.Select(p => Arg<object>.Is.Anything)
.ToArray();
}
But the answer by Sergey Berezovskiy seems a bit simpler.
Perhaps the easiest thing to do would be to pass a null ref to the calling class. Your SUT should throw a NullReferenceException if it attempts to use it. This is possibly the simplest thing that will work.
However, if the SUT checks for null, then this won't work.

C# Action<> with Func<> parameter

I have the following method that I can't figure out correct syntax to call:
public T GetAndProcessDependants<C>(Func<object> aquire,
Action<IEnumerable<C>, Func<C, object>> dependencyAction) {}
I'm trying to call it like this:
var obj = MyClass.GetAndProcessDependants<int>(() => DateTime.Now,
(() => someList, (id) => { return DoSomething(x); }) }
Edited:
thx everyone, you guys helped turned on a light bulb in my head. here is what i did:
var obj = MyClass.GetAndProcessDependants<int>(
() => DateTime.Now,
(list, f) =>
{
list = someList;
f = id => { return DoSomething(id); };
});
not sure why i even an issue with this. it's one of those days i guess..
thx
Your lambda syntax is totally wrong.
You need to create a single lambda expression with two parameters:
(list, id) => DoSomething(...)
Right now the function is only accepting a single argument, when it asks for two!
You need to accept a list argument, such as (list, id) => {}
Just looking at the description above, it looks like the call should be:
var obj = MyClass.GetAndProcessDependants<int>(() => DateTime.Now,
(seq, fun) => { /* do something with seq and fun */ });
The key is since you are passing an Action that takes a Func, the caller is (most likely) going to be the one passing that Func into your Action. So you just specify how that Func is applied to the sequence passed in (if I'm reading the prototype correctly).
var obj = MyClass.GetAndProcessDependants<int>(
() => DateTime.Now,
(someList, id) => DoSomething(x)
);

Categories