我有一个对象,如果它实现特定类型的接口,我想调用某些方法。
我正在检查以下通用接口。
foreach (var iFace in objectType.GetInterfaces())
{
if (iFace.IsGenericType && iFace.GetGenericTypeDefinition() == typeof(INotify<>))
{
//fails to compile because object isn't the correct type.
doSomethingWithINotifyObject(notifyObject)
}
//do other things if different interfaces
}
我不知道该怎么做是将对象强制转换为调用doSomethingWithINotifyObject
的正确类型
此示例中的方法看起来像这样
private void doSomethingWithINotifyObject<T>(INotify<T> notify) where T : EventArgs, INotificationArgs
{
//do stuff with notification object
}
INotify接口定义为
public interface INotify<T> where T: EventArgs, INotificationArgs
{
//notify stuff
}
有什么方法可以将对象强制转换为INotify<T> where T : EventArgs, INotificationArgs
而不关心T实际是什么?
我尝试过制作类似于以下内容的通用方法
typeof(MyClass)
.GetMethod("doSomethingWithINotifyObject")
.MakeGenericMethod(notifyObject.GetType())
.Invoke(this, new object[] { notifyObject });
我得到了以下运行时异常
运行时异常(第13行):GenericArguments [0],“ Void doSomethingWithINotifyObjectT”上的“ MyClass + doSomethingWithINotifyObject”违反了类型“ T”的约束。
堆栈跟踪:
[System.Security.VerificationException:方法MyClass.doSomethingWithINotifyObject:类型参数'MyClass + doSomethingWithINotifyObject'违反了类型参数'T'的约束。 在System.RuntimeMethodHandle.GetStubIfNeeded(RuntimeMethodHandleInternal方法,RuntimeType声明类型,RuntimeType [] methodInstantiation) 在System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type [] methodInstantiation)
[System.ArgumentException:GenericArguments [0],“ Void doSomethingWithINotifyObjectT”上的“ MyClass + doSomethingWithINotifyObject”违反了类型“ T”的约束。] 在System.RuntimeType.ValidateGenericArguments处(MemberInfo定义,RuntimeType [] genericArguments,异常e) 在System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type [] methodInstantiation) 在MyClass.Main()处:第13行
我在.NET上有一个这种情况的例子,这里https://dotnetfiddle.net/ZWMJ4x
答案 0 :(得分:1)
否,您需要知道T
是什么,因为否则类型系统将无法检查您的参数是否正确,或者返回值类型是否正确,等等。
您可以通过反射来做所有事情,并绕过所有这些,或者如果您真的不在乎T
只是将这些方法放在通用接口中并强制转换为该接口(毕竟不应该包含T。
答案 1 :(得分:1)
typeof(MyClass)
.GetMethod("doSomethingWithINotifyObject")
.MakeGenericMethod(notify.GetType())
.Invoke(null, new object[] { notify });
不起作用,因为您的Notify
类不是通用的,即使它确实实现了通用的INotify<FooBarClass>
。需要传递给MakeGenericMethod
的是Notify
使用的实际类型参数:
typeof(MyClass)
.GetMethod("doSomethingWithINotifyObject")
.MakeGenericMethod(iFace.GetGenericArguments())
.Invoke(null, new object[] { notify });
答案 2 :(得分:0)
如果INotify
相对于T是协变的,则可能没有反射。
由于类型约束由两部分组成,因此需要定义一个实现这两个类型的基类,并从中派生INotify<>
类。
public interface INotificationArgs
{
}
public interface INotify<out T> where T: EventArgs, INotificationArgs
{
void PrintName();
}
public class MyEventArgsBase : EventArgs, INotificationArgs {}
public class MyEventArgs1 : MyEventArgsBase {}
public class MyEventArgs2 : MyEventArgsBase {}
public class MyEventArgs3 : MyEventArgsBase {}
class MyClass<T> : INotify<T> where T : EventArgs, INotificationArgs
{
public string Name { get; set; }
public MyClass(string name) { Name = name; }
public void PrintName()
{
Console.WriteLine(Name);
}
}
public class Program
{
private static void doSomethingWithINotifyObject<T>(INotify<T> notify) where T : EventArgs, INotificationArgs
{
notify.PrintName();
}
public static void Main()
{
object[] tests = new object []
{
new MyClass<MyEventArgs1>("1"),
new MyClass<MyEventArgs2>("2"),
new MyClass<MyEventArgs3>("3")
};
foreach (var o in tests)
{
var i = o as INotify<MyEventArgsBase>;
if (i != null)
{
doSomethingWithINotifyObject(i);
}
}
}
}
输出:
1
2
3