Первое, на что нужно обратить внимание, это то, что аноним namespace
не совпадает с namespace
.
namespace
{
bool operator==(const Foo&, const Foo&) {...}
}
- это действительно что-то вроде
namespace ANameUniqueToTheFile
{
bool operator==(const Foo&, const Foo&) {...}
}
using ANameUniqueToTheFile;
с тем недостатком, что язык не дает вам возможности получить имя namespace
.
По этой причине, функция operator==
, определенная в анонимном namespace
, не найдена с использованием ADL.
Я понимаю, почему вы хотите поместить функцию operator==
в namespace
. Один из возможных способов сделать это - файл #include
.h, который определяет struct
внутри именованного namespace
.
FooWrapper.h:
namespace MyApp
{
#include "foo.h"
// Declare the function.
bool operator==(Foo const& lhs, Foo const& rhs);
}
FooWrapper.cpp
#include "FooWrapper.h"
namespace MyApp
{
// Implement the function.
bool operator==(Foo const& lhs, Foo const& rhs) { ... }
}
Я понимаю, что немного упрощаю то, что в "foo.h". Добавление всех из них в namesapce MyApp
может быть неуместным, особенно если «foo.h» включает в себя другие файлы .h и / или стандартные заголовочные файлы. Я надеюсь, что это даст вам некоторые идеи о том, как решить проблему.
Если поместить все «foo.h» в namespace MyApp
не гладко, вероятно, будет целесообразно определить функцию operato==
в глобальной области видимости.
Я не могу найти способ использовать GetMethod, который сделал бы то, что Вы хотите. Но можно получить все методы и пройти список, пока Вы не находите метод, который Вы хотите.
Помните, что необходимо назвать MakeGenericMethod, прежде чем можно будет на самом деле использовать его.
var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo foundMi = allMethods.FirstOrDefault(
mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2);
if (foundMi != null)
{
MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)});
Example example= new Example();
closedMi.Invoke(example, new object[] { 5 });
}
Вот острота Linq для того, в чем Вы нуждаетесь:
MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);
Вот ответы на Ваши вопросы наряду с примером:
Да, хотя существует две вещи действительно для знания здесь с общими методами, выводом типа и разрешением метода перегрузки. Вывод типа происходит во время компиляции, прежде чем компилятор пытается разрешить подписи перегруженного метода. Компилятор применяет логику вывода типа ко всем общим методам, которые совместно используют то же имя. На шаге разрешения перегрузки компилятор включает только те общие методы для который вывод типа, за которым следуют. Больше здесь...
См. полный код программы Консольного приложения в качестве примера ниже этого шоу, как несколько вариантов метода Foo могут быть указаны в создании объекта MethodInfo и затем вызвали использование Дополнительного метода:
Program.cs
class Program
{
static void Main(string[] args)
{
MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string) },
new[] { typeof(int) },
typeof(void));
MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string), typeof(int) },
new[] { typeof(int) },
typeof(void));
MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string) },
new[] { typeof(string) },
typeof(void));
MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string), typeof(int) },
new[] { typeof(int), typeof(string) },
typeof(string));
Console.WriteLine(foo1.Invoke(null, new object[] { 1 }));
Console.WriteLine(foo2.Invoke(null, new object[] { 1 }));
Console.WriteLine(foo3.Invoke(null, new object[] { "s" }));
Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" }));
}
}
Example.cs:
public class Example
{
public static void Foo<T>(int ID) { }
public static void Foo<T, U>(int ID) { }
public static void Foo<T>(string ID) { }
public static string Foo<T, U>(int intID, string ID) { return ID; }
}
Extensions.cs:
public static class Extensions
{
public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
{
MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
where m.Name == name &&
m.GetGenericArguments().Length == genericArgTypes.Length &&
m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) &&
m.ReturnType == returnType
select m).Single().MakeGenericMethod(genericArgTypes);
return foo1;
}
}
I make a little modification of your lambda query.
When the parameter type si generic you must make that like that :
I add pi.ParameterType.GetGenericTypeDefinition()
and
(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
In this way the method working very fine
MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
where m.Name == name
&& m.GetGenericArguments().Length == genericArgTypes.Length
&& m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) &&
(returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
select m).FirstOrDefault();
if (foo1 != null)
{
return foo1.MakeGenericMethod(genericArgTypes);
}
return null;
Example :
With the modification of the method i can call этот метод расширения
public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter)
С моим новым Помощником, подобным этому
var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>));
Подпись моего помощника:
public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)