良心与思想

偶的代码生涯
随笔 - 32, 评论 - 243, 引用 - 31

导航

关于

最近在学习windbg

标签

每月存档

最新留言

广告

 

背景:两个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

留言反馈

#回复: 关于InvokeMember的一个郁闷的错误 编辑
鞠驴,我是老袁.有空去我的站点玩玩.http://hi.baidu.com/yuange1975
2007-10-21 18:51:00 | [匿名:yuange]
#回复: 关于InvokeMember的一个郁闷的错误 编辑
我搞错了,哈!

那个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;
}
}
2007-08-09 10:58:00 | [匿名:juqiang]
#回复: 关于InvokeMember的一个郁闷的错误 编辑
使用GetMethod取回对应参数的方法对象,譬如

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});


}
}

2007-08-09 10:35:00 | [匿名:saucer]
#回复: 关于InvokeMember的一个郁闷的错误 编辑
我的意思是,如果有方法:
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出来的。
2007-08-09 09:50:00 | [匿名:juqiang]
#回复: 关于InvokeMember的一个郁闷的错误 编辑
to saucer老大,欢迎捧场!

我那个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)不会出错的情况。

晕了……
2007-08-09 09:47:00 | [匿名:juqiang]
#回复: 关于InvokeMember的一个郁闷的错误 编辑
你的AddBall方法是public的么,不是的话,你需要使用BindingFlags.NonPublic

我做了一个测试

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);
}
}


没有问题
2007-08-09 03:51:00 | [匿名:saucer]
#回复: 关于InvokeMember的一个郁闷的错误 编辑
不可能和panel的字段类型有关的.你肯定是哪里搞错了.
2007-08-09 01:09:00 | [匿名:Lostinet]
博客主人设置本博客不允许匿名用户发表言论,请登录后再试

Powered by: Joycode.MVC引擎 0.5.2.0