2013-08-24 73 views
2

我已阅读其他一些答案以进行动态强制转换,但我不确定它们是否解决了我想解决的问题,因此提出了问题。动态强制转换为通用接口类型

我有一个接口

public interface ICustomTransmitter<T> : IDataTransmitter where T : EventArgs 
{ 
    event EventHandler<T> DataEvent; 
} 

和一组功能,让我得到运行时的泛型类型参数。这是为了强制转换为该类型和挂钩的特定事件(这被认为是代码,所以请温柔)

public bool IsTypeOf(Type baseType, Type interfaceType, 
    out Type argumenType) 
{ 
    var interfaces = baseType.GetInterfaces(); 
    argumenType = null; 

    foreach (Type @interface in interfaces) 
    { 
     if (@interface.Name != interfaceType.Name) continue; 
     if (@interface.IsGenericType) 
     { 
      argumenType = @interface.GetGenericArguments()[0]; 
     } 
     return true; 
    } 
    return false; 
} 

和使用上述

Type argument; 
var generic = typeof (ICustomTransmitter<>); 
if (IsTypeOf(receiver.GetType(),generic ,out argument)) 
{ 
    var created = generic.MakeGenericType(new[] {argument}); 

    //the line of code missing is below 
    receiver as created 
} 

神奇的功能是它可以将接收器投射到创建的类型?此外,我需要有一个解决方案,在网点3.5和网点4都可以使用。

+0

我编辑了您的标题。请参阅:“[应该在其标题中包含”标签“](http://meta.stackexchange.com/questions/19190/)”,其中的共识是“不,他们不应该”。 –

+0

谢谢@JohnSaunders,注意到 – Bernard

回答

2

没有一种铸件可以做到这一点。 Casting是关于检查运行时类型是否是已知的编译时类型。你甚至没有编译时间类型。

你需要做的是使用反射来寻找接口,提取泛型类型参数,创建一个兼容的委托,并挂接委托处理程序。你有IsOfType的第一个步骤。

当你连接一个事件处理程序时,你正在调用它的add方法。编译器为该方法生成一个名为“add_EventName”形式的名称。以下是一些示例代码,可以完成所有这些工作:

using System; 
using System.Reflection; 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     object o = new CustomArgsTransmitter(); 

     // make sure we've got the interface 
     var interf = o.GetType().GetInterface("ICustomTransmitter`1"); 

     // get the arg type. 
     var argType = interf.GetGenericArguments()[0]; 

     // create a delegate for the handler based on the arg type above 
     var handlerMethodInfo = typeof(Program).GetMethod("Handler", BindingFlags.Static | BindingFlags.Public) 
     var del = Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(argType), handlerMethodInfo); 

     // Invoke the add method of the event. 
     o.GetType().InvokeMember("add_DataEvent", BindingFlags.InvokeMethod, null, o, new object[] { del }); 

     // just test code at this point. 
     // fire event to make sure it is signed up. 
     // It should print a message to the console. 
     ((CustomArgsTransmitter)o).FireEvent(); 

    } 

    public static void Handler(object sender, EventArgs e) 
    { 
     Console.WriteLine("Got event {0} from {1}", e, sender); 
    } 
} 

public interface IDataTransmitter { } 

public interface ICustomTransmitter<T> : IDataTransmitter where T : EventArgs 
{ 
    event EventHandler<T> DataEvent; 
} 

public class MyArgs : EventArgs { } 

public class CustomArgsTransmitter : ICustomTransmitter<MyArgs> 
{ 
    public event EventHandler<MyArgs> DataEvent; 

    public void FireEvent() 
    { 
     DataEvent(this, new MyArgs()); 
    } 
} 
+0

我的天啊,那是一个美丽的解决方案。我已经扩展它来处理一个自定义的事件类型,并且一旦我对这些概念有所了解的话,它都可以很好地工作!感谢一大群人。不要以为我会亲自到达那里! – Bernard

1

不可以。您不能将表达式转换为编译时未知的类型。 (通过“已知”,我的意思是可以解析为Type,其通用类型参数已关闭。)

说了这么多,我认为可以通过使用表达式API。这个想法是,你会建立一个你确定类型的lambda表达式(可以是强类型的),编译它,然后在你的对象上执行它来执行转换。如果你100%需要这样做,这是我看的方向。