将具有通用方法的接口实例转换为操作
Converting instance of Interface with generic method to Action
我正在努力使用我可以使用反射检索的 MethodInfo
创建 Action<>
的实例。
使用下面的示例,我可以轻松地在我的对象上调用自定义方法,但我真的很想将它们转换为 Actions。
我已经尝试使用 Delegate.CreateDelegate
来完成它,但我似乎无法将其用于 return 具有通用类型的 Action。
例子
我创建了以下界面:
interface IMyTest { } // Marker interface
interface<TInput> IMyTest : IMyTest {
void MyMethod(TInput input);
}
然后我继承接口在一个class:
class MyClass : IMyTest<DateTime>, IMyTest<int> {
void MyMethod(DateTime input) {
// Do something
}
void MyMethod(int input) {
// Do something else
}
}
然后我创建了一个使用反射从接口实例中查找和调用 "MyMethod" 的方法:
void DoCallMyMethod(object target, object input) {
IEnumerable<Type> interfaces = target.GetType().GetInterfaces()
.Where(x => typeof(IMyTest).IsAssignableFrom(x) && x.IsGenericType);
foreach (Type @interface in interfaces) {
Type type = @interface.GetGenericArguments()[0];
MethodInfo method = @interface.GetMethod("MyMethod", new Type[] { type });
if (method != null) {
method.Invoke(target, new[] { input });
}
}
}
最后我把它们放在一起:
MyClass foo = new MyClass();
DoCallMyMethod(foo, DateTime.Now);
DoCallMyMethod(foo, 47);
我想要什么
在 DoCallMyMethod
内部,我希望将 MethodInfo method
转换为通用 Action
,这样结果将是这样的:
Action<type> myAction = method;
但这显然行不通
我找到了一些类似的 SO 帖子(但 none 完全涵盖了我的情况),最终得到了类似于此的答案:
Action<object> action =
(Action<object>)Delegate.CreateDelegate(typeof(Action<object>), target, method);
但这行不通,因为 "Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type."
我怎样才能得到指定 type
作为其输入类型的 Action,同时仍然保留对象引用(没有新实例出现)?
您无法从 MyMethod
之一创建 Action<object>
,因为该方法需要特定对象的类型(int
、DateTime
),并且如果您将其视为 Action<object>
您可以使用任何类型的对象调用它。
由于您需要的是 return 一个 Action<T>
,因此不需要将输入值传递给 DoCallMyMethod
方法。您可以将输入类型作为通用参数传递:
public Action<T> DoCallMyMethod<T>(object target)
{
var @interface = typeof(IMyTest<T>);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
var action = Delegate.CreateDelegate(typeof(Action<T>), target, method) as Action<T>;
return action;
}
}
return null;
}
然后,像这样使用它:
MyClass foo = new MyClass();
var action1 = DoCallMyMethod<DateTime>(foo);
var action2 = DoCallMyMethod<int>(foo);
action1(DateTime.Now);
action2(47);
如果您在编译时不知道输入的类型,您可以试试这个:
public Delegate DoCallMyMethod(object target, Type inputType)
{
var @interface = typeof(IMyTest<>).MakeGenericType(inputType);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
var @delegate = Delegate.CreateDelegate(typeof(Action<>).MakeGenericType(inputType), target, method);
return @delegate;
}
}
return null;
}
并像这样使用它:
MyClass foo = new MyClass();
var action1 = DoCallMyMethod(foo, typeof(DateTime)) as Action<DateTime>;
var action2 = DoCallMyMethod(foo, typeof(int)) as Action<int>;
action1(DateTime.Now);
action2(47);
//or
int input = 47;
var @delegate = DoCallMyMethod(foo, input.GetType());
@delegate.DynamicInvoke(input);
但是,如果您需要 return 一个 Action<object>
,您可以执行一个操作来接收对象并在对象的类型有效时调用该方法:
public Action<object> DoCallMyMethod(object target, Type inputType)
{
var @interface = typeof(IMyTest<>).MakeGenericType(inputType);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
Action<object> action = obj =>
{
if (obj.GetType().IsAssignableFrom(inputType))
method.Invoke(target, new object[] { obj });
};
return action;
}
}
return null;
}
还有...
MyClass foo = new MyClass();
Action<object> action = DoCallMyMethod(foo, typeof(int));
action(47); // MyMethod(int) is called.
action("..."); // Nothing happens.
现在您有一个 Action<object>
仅在传递整数时才调用 MyMethod(int)
。
我正在努力使用我可以使用反射检索的 MethodInfo
创建 Action<>
的实例。
使用下面的示例,我可以轻松地在我的对象上调用自定义方法,但我真的很想将它们转换为 Actions。
我已经尝试使用 Delegate.CreateDelegate
来完成它,但我似乎无法将其用于 return 具有通用类型的 Action。
例子
我创建了以下界面:
interface IMyTest { } // Marker interface
interface<TInput> IMyTest : IMyTest {
void MyMethod(TInput input);
}
然后我继承接口在一个class:
class MyClass : IMyTest<DateTime>, IMyTest<int> {
void MyMethod(DateTime input) {
// Do something
}
void MyMethod(int input) {
// Do something else
}
}
然后我创建了一个使用反射从接口实例中查找和调用 "MyMethod" 的方法:
void DoCallMyMethod(object target, object input) {
IEnumerable<Type> interfaces = target.GetType().GetInterfaces()
.Where(x => typeof(IMyTest).IsAssignableFrom(x) && x.IsGenericType);
foreach (Type @interface in interfaces) {
Type type = @interface.GetGenericArguments()[0];
MethodInfo method = @interface.GetMethod("MyMethod", new Type[] { type });
if (method != null) {
method.Invoke(target, new[] { input });
}
}
}
最后我把它们放在一起:
MyClass foo = new MyClass();
DoCallMyMethod(foo, DateTime.Now);
DoCallMyMethod(foo, 47);
我想要什么
在 DoCallMyMethod
内部,我希望将 MethodInfo method
转换为通用 Action
,这样结果将是这样的:
Action<type> myAction = method;
但这显然行不通
我找到了一些类似的 SO 帖子(但 none 完全涵盖了我的情况),最终得到了类似于此的答案:
Action<object> action =
(Action<object>)Delegate.CreateDelegate(typeof(Action<object>), target, method);
但这行不通,因为 "Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type."
我怎样才能得到指定 type
作为其输入类型的 Action,同时仍然保留对象引用(没有新实例出现)?
您无法从 MyMethod
之一创建 Action<object>
,因为该方法需要特定对象的类型(int
、DateTime
),并且如果您将其视为 Action<object>
您可以使用任何类型的对象调用它。
由于您需要的是 return 一个 Action<T>
,因此不需要将输入值传递给 DoCallMyMethod
方法。您可以将输入类型作为通用参数传递:
public Action<T> DoCallMyMethod<T>(object target)
{
var @interface = typeof(IMyTest<T>);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
var action = Delegate.CreateDelegate(typeof(Action<T>), target, method) as Action<T>;
return action;
}
}
return null;
}
然后,像这样使用它:
MyClass foo = new MyClass();
var action1 = DoCallMyMethod<DateTime>(foo);
var action2 = DoCallMyMethod<int>(foo);
action1(DateTime.Now);
action2(47);
如果您在编译时不知道输入的类型,您可以试试这个:
public Delegate DoCallMyMethod(object target, Type inputType)
{
var @interface = typeof(IMyTest<>).MakeGenericType(inputType);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
var @delegate = Delegate.CreateDelegate(typeof(Action<>).MakeGenericType(inputType), target, method);
return @delegate;
}
}
return null;
}
并像这样使用它:
MyClass foo = new MyClass();
var action1 = DoCallMyMethod(foo, typeof(DateTime)) as Action<DateTime>;
var action2 = DoCallMyMethod(foo, typeof(int)) as Action<int>;
action1(DateTime.Now);
action2(47);
//or
int input = 47;
var @delegate = DoCallMyMethod(foo, input.GetType());
@delegate.DynamicInvoke(input);
但是,如果您需要 return 一个 Action<object>
,您可以执行一个操作来接收对象并在对象的类型有效时调用该方法:
public Action<object> DoCallMyMethod(object target, Type inputType)
{
var @interface = typeof(IMyTest<>).MakeGenericType(inputType);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
Action<object> action = obj =>
{
if (obj.GetType().IsAssignableFrom(inputType))
method.Invoke(target, new object[] { obj });
};
return action;
}
}
return null;
}
还有...
MyClass foo = new MyClass();
Action<object> action = DoCallMyMethod(foo, typeof(int));
action(47); // MyMethod(int) is called.
action("..."); // Nothing happens.
现在您有一个 Action<object>
仅在传递整数时才调用 MyMethod(int)
。