背景:两个CustomControl,一个叫做MyPanel,是一个M*N的格子,一个叫做Ball,是一个球。球可以放在panel的格子中,可以鼠标进行drag & drop.
直接call很简单,没有任何问题。但是通过reflection,碰到了郁闷的事情。虽然最终搞定了,但是要看过InvokeMember的代码才能知道为什么。
代码:
Object panel = null;
Type tpanel = null;
private void ReflectionForm_Load(object sender, EventArgs e)
{
Assembly asm = Assembly.LoadFile(@"D:\test\WindowsApplication5\MyLibrary\bin\Debug\mylibrary.dll");
tpanel = asm.GetType("MyLibrary.MyPanel");
panel = tpanel.InvokeMember("", BindingFlags.CreateInstance, null, this, new object[] { });
(panel as Control).Location = new Point(100, 100);
this.Controls.Add(panel as Control);
}
出错的地方:
tpanel.InvokeMember("AddBall", BindingFlags.Instance | BindingFlags.Public|BindingFlags.InvokeMethod,
null, panel, new object[] { obj });
如果上面的panel是object类型,那么一切正常。如果是Control类型,即,我声明为:Control panel,然后
object obj = tpanel.InvokeMember("", BindingFlags.CreateInstance, null, this, new object[] { });
panel = object as Control;
panel.Location = new Point(100,100);
this.Controls.Add(panel);
那么上面的InvokeMember就会提示我:Method not found!如果我修改BindingFlags,去掉Method,那么没有MethodNotFound的exception,但是会有“请使用InvokeMethod,Set/Get Field之类的提示”。如果加上,就是MethodNotFound,真是faint!
google了一些,貌似有些人碰到过,一个post上面说,arguments的类型必须要和method的类型完全一致才可以。我想,如果Panel当作control来用,那么control -> Ball类型会无法转换的,而object -> Ball是允许的。
哪位高手帮忙解释一下?谢谢!
打印 | 张贴于 2007-08-08 21:20:00 | Tag:VS.NET
留言反馈
http://foto-segretaria-scopata.vestito-thn.cn
http://sborrata-dell-uomo-peloso.play-thn.cn
http://video-cazzo-nel-culo.play-thn.cn
http://sesso-roberta-missoni.vestito-thn.cn
http://racconto-erotici-sadomaso.gradis-omt.info
http://Hana-Melonova.ivana-omt.info
http://studentessa-scopano-gratis.ivana-omt.info
那个InvokeMember中,mi是AddBall,但是最后的args应该是Ball类型,而不是panel类型!即,那个obj被我搞成MyPanel了,而实际上obj应该是a ball.
Anyway,下面这段代码是根据RuntimeType.InvokeMember的片断写的。
private void button2_Click(object sender, EventArgs e)
{
Assembly asm = Assembly.LoadFile(@"D:\test\WindowsApplication5\MyLibrary\bin\Debug\mylibrary.dll");
tpanel = asm.GetType("MyLibrary.MyPanel");
Binder binder = Type.DefaultBinder;
BindingFlags bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod;
object[] args = new object[]{panel};
MethodInfo[] infoArray3 = tpanel.GetMember("AddBall", MemberTypes.Method, bf) as MethodInfo[];
object objstate = null;
try
{
binder.BindToMethod(bf, infoArray3, ref args, null, null, new string[] { "AddBall" }, out objstate);
}
catch (MissingMethodException ex)
{
throw ex;
}
catch (Exception be)
{
throw be;
}
}
1. MyLibrary.cs (编译成mylibrary.dll)
using System;
using System.Windows.Forms;
namespace MyLibrary
{
public class Ball : Control
{
}
public class MyPanel : Panel
{
public void AddBall(int row)
{
Console.WriteLine("AddBall(int row)");
}
public void AddBall(int row, int col, Ball ball)
{
Console.WriteLine("AddBall(int row, int col, Ball ball)");
}
public void AddBall(int row, int col, Object obj)
{
Console.WriteLine("AddBall(int row, int col, Object obj)");
}
public void AddBall(int row, int col, Control obj)
{
Console.WriteLine("AddBall(int row, int col, Control obj)");
}
}
}
2. TestBall.cs
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
class TestBall
{
static void Main()
{
Assembly asm = Assembly.LoadFile(@"d:\labs\MyLibrary.dll");
Type tball = asm.GetType("MyLibrary.Ball");
Type tpanel = asm.GetType("MyLibrary.MyPanel");
Control p = (Control)Activator.CreateInstance(tpanel);
Object o = Activator.CreateInstance(tball);
string mn = "AddBall";
Type[] pars = new Type[]{typeof(int)};
MethodInfo mi = tpanel.GetMethod(mn,pars);
mi.Invoke(p,new object[]{1});
pars = new Type[]{typeof(int),typeof(int),tball};
mi = tpanel.GetMethod(mn,pars);
mi.Invoke(p,new object[]{1,1,o});
pars = new Type[]{typeof(int),typeof(int),typeof(Object)};
mi = tpanel.GetMethod(mn,pars);
mi.Invoke(p,new object[]{1,1,o});
pars = new Type[]{typeof(int),typeof(int),typeof(Control)};
mi = tpanel.GetMethod(mn,pars);
mi.Invoke(p,new object[]{1,1,o});
}
}
public void AddBall(int row);
public void AddBall(int row, int col, Ball ball);
public void AddBall(int row, int col, Object obj);
public void AddBall(int row, int col, Control obj);
因为overload必须要保证参数个数+类型不同,所以参数类型必须要匹配。但是我的ball是从Control继承的啊!当然也是从Object出来的。
我那个InvokeMember里面,最后的args[]是有一个obj的,就是那个ball,执行的事AddBall。
昨晚突然想起来,CLR应该是要保证参数类型完全一致,才做的这个检查。否则,overload的所有方法,都搞不定了。
但是我如果这么做的话:
MyLibrary.Ball b = new MyLibrary.Ball(0, 0, "hello");
Control c = b as Control;
Object o = b as object;
myPanel1.AddBall(c);
myPanel1.AddBall(o);
后面的两句AddBall都会产生CTE,而不是原文中,只有AddBall(c)会出错,AddBall(o)不会出错的情况。
晕了……
我做了一个测试
1. MyLibrary.cs (编译成mylibrary.dll)
using System;
using System.Windows.Forms;
namespace MyLibrary
{
public class Ball : Control
{
}
public class MyPanel : Panel
{
/*public void AddBall(Ball b)
{
Controls.Add(b);
}*/
public Ball AddBall()
{
Ball b = new Ball();
Controls.Add(b);
return b;
}
}
}
2. TestBall.cs
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
class TestBall
{
static void Main()
{
Assembly asm = Assembly.LoadFile(@"d:\labs\csharp\mylibrary.dll");
Type tpanel = asm.GetType("MyLibrary.MyPanel");
Control b = (Control)tpanel.InvokeMember("AddBall", BindingFlags.CreateInstance, null, null, new object[] {});
b.Location = new Point(100, 100);
Console.WriteLine(b.Location);
Control p = (Control)Activator.CreateInstance(tpanel);
Control b2 = (Control)tpanel.InvokeMember("AddBall", BindingFlags.Instance | BindingFlags.Public|BindingFlags.InvokeMethod,
null, p, new object[] {});
b2.Location = new Point(200, 200);
Console.WriteLine(b2.Location);
}
}
没有问题