反射问题,高手请进
采用反射创建的对象无法进行类型转换,详细如下
一个基于WinForm的程序,为了扩展功能,实现我自己的接口,如下:
public partial class frmMain : Form,IMyApp
{
.....
}
IMyApp里实现对frmMain的几个属性调用,如:
public interface IMyApp
{
string Caption
{
get;
set;
}
FormWindowState WindowState
{
get;
set;
}
Size WindowSize
{
get;
set;
}
StatusStrip StatusBar
{
get;
}
MenuStrip Menus
{
get;
}
}
同时又写了个IPlugIn接口,如下:
public interface IPlugIn : IDisposable
{
void Initialize(IGISApp app);
}
另外建立一个类工程,写了一个从IPlugIn 派生的类,编译为Dll,放在WinForm目录下面,通过下面语句动态加载,创建类的实例,但是,提示类型不能转换:
LoadPlugs在Form的Load事件里调用
private void LoadPlugs()
{
string fileName = Application.StartupPath + "\\ClassLibrary1.dll";
Assembly asm = Assembly.LoadFile(fileName);
Type[] types = asm.GetTypes();
foreach (Type type in types)
{
if (type.GetInterface("IPlugIn") != null)
{
Object obj = Activator.CreateInstance(type);
IPlugIn plug = (IPlugIn)obj; //这里出错,提示为'无法将类型为“ClassLibrary1.Class1”的对象强制转换为类型“MyAPP.Interface.IPlugIn”'
plug.Initialize(this);
}
}
}
哪位能解决,分不够可以再加。
如果这种调用不行,该用哪种方式实现我的功能??
问题点数:50、回复次数:35Top
1 楼fengfangfang()回复于 2006-09-25 09:57:20 得分 0
private static IPetShopCacheDependency LoadInstance(string className) {
string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
string fullyQualifiedClass = path + "." + className;
// Using the evidence given in the config file load the appropriate assembly and class
return (IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);
}Top
2 楼fengfangfang()回复于 2006-09-25 09:58:00 得分 0
PetShop4.0中的应用
http://blog.csdn.net/fengfangfang/archive/2006/09/06/1185077.aspxTop
3 楼Knight94(愚翁)回复于 2006-09-25 12:07:58 得分 0
yun~
接口对象不能直接实例化,需要通过实现接口的类型对象进行转换。
也就是说需要通过实现IPlugIn接口类型去转换得到IPlugIn对象。
目前从你的说明来说,好像并没有对IPlugIn并没有进行实现。Top
4 楼wl22817560()回复于 2006-09-25 12:20:40 得分 0
http://community.csdn.net/Expert/topic/5045/5045049.xml?temp=.7106897
借点人气 找人帮帮忙
Top
5 楼liyihui2001(辉)回复于 2006-09-25 13:49:13 得分 0
Knight94(愚翁) :
是不是没有看清楚我写的?我从IPlugIn派生了一个类,实现了IPlugIn的接口,编译成一个Dll了,怎么说没有对IPlugIn进行实现呢?Top
6 楼Knight94(愚翁)回复于 2006-09-25 13:59:03 得分 0
to 是不是没有看清楚我写的?我从IPlugIn派生了一个类,实现了IPlugIn的接口,编译成一个Dll了,怎么说没有对IPlugIn进行实现呢?
Sorry!
那么不能直接通过createinstance创建IPlugIn接口对象,需要通过用其派生的类型产生对象,然后转化成IPlugIn接口对象。Top
7 楼fengfangfang()回复于 2006-09-25 14:04:12 得分 0
ClassLibrary1.Class1的代码贴出来看看Top
8 楼fengfangfang()回复于 2006-09-25 14:06:41 得分 0
使用Assembly.Load方法和Assembly.CreateInstance,不要使用Activator.CreateInstanceTop
9 楼liyihui2001(辉)回复于 2006-09-25 14:08:00 得分 0
我跟了一下,在循环中得到的types中的IPlugIn接口已经通过type.GetInterface("IPlugIn") != null 过滤掉了,确实不是实例化IPlugIn接口的,创建成功的是ClassLibrary1.Class1的对象,可为啥就是不能转换成接口呢?
创建的对象都是正确的,就是转换不让转,快帮帮我吧Top
10 楼hdt(倦怠)回复于 2006-09-25 14:09:07 得分 0
Object obj = Activator.CreateInstance(type);
IPlugIn plug = (IPlugIn)obj; //这里出错,提示为'无法将类型为“ClassLibrary1.Class1”的
===================
obj is object is can't convert
try
Object obj = Activator.CreateInstance(type);
IPlugIn plug = obj as IPlugIn;Top
11 楼liyihui2001(辉)回复于 2006-09-25 14:09:56 得分 0
Class1的代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace ClassLibrary1
{
public class Class1 : SharpMapClient.Interface.IPlugIn
{
#region IPlugIn 成员
public void Initialize(SharpMapClient.IGISApp app)
{
MenuStrip ms = app.Menus;
ToolStripMenuItem item = ms.Items[1] as ToolStripMenuItem;
item.DropDownItems.Add("AAAA");
}
#endregion
#region IDisposable 成员
public void Dispose()
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
}
}Top
12 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-09-25 14:12:51 得分 0
type.GetInterface(typeof(IPlugIn).Name) == typeof( IPlugIn ) !!!Top
13 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-09-25 14:13:34 得分 5
类型名字相同,命名空间不一定相同,就算全名相同也不一定是同一个类型。Top
14 楼viena(维也纳N02)回复于 2006-09-25 14:14:18 得分 0
//if (type.GetInterface("IPlugIn") != null)
这样得到的未必是实现此接口的类
也可能是继承此接口的接口,此时直接创建实例肯定会出错Top
15 楼liyihui2001(辉)回复于 2006-09-25 14:16:34 得分 0
fengfangfang() :
Assembly.CreateInstance和Activator.CreateInstance结果是一样的,创建的对象都是正确的,转换时就报“InvalidCastException"异常。Top
16 楼liyihui2001(辉)回复于 2006-09-25 14:22:12 得分 0
hdt(倦怠) :
用as转换早就试过,这种方法不报异常,就是转换后为null了。Top
17 楼hdt(倦怠)回复于 2006-09-25 14:22:48 得分 5
IPlugIn 单独做个组件dll,其他工程同时引用同一个IPlugIn,怀疑是你们引用的是不同IPlugIn
Top
18 楼Samen168(Code to coding)回复于 2006-09-25 14:22:52 得分 0
IPlugIn plug = (IPlugIn)obj; //这里出错,提示为'无法将类型为“ClassLibrary1.Class1”的对象强制转换为类型“MyAPP.Interface.IPlugIn”'
SharpMapClient.Interface.IPlugIn
这是同名的两个不同接口Top
19 楼hdt(倦怠)回复于 2006-09-25 14:24:35 得分 0
IPlugIn最好用强名称控制,否则易出现dll hole问题。
Top
20 楼liyihui2001(辉)回复于 2006-09-25 14:24:53 得分 0
Ivony()和viena(维也纳nn):
创建的对象是正确的,肯定是一个类型,这点能保证,我在Class1里加了个属性,创建的对象里都能跟进去看到这个属性的值。Top
21 楼Knight94(愚翁)回复于 2006-09-25 14:26:57 得分 0
正如“Samen168(技术==>价值) ”所说,两者不是同一个类型
Top
22 楼fengfangfang()回复于 2006-09-25 14:32:10 得分 0
“MyAPP.Interface.IPlugIn”'
SharpMapClient.Interface.IPlugIn
确实是两个接口Top
23 楼viena(维也纳N02)回复于 2006-09-25 14:33:53 得分 0
//IPlugIn plug = (IPlugIn)obj;
把鼠标指针放到IPlugIn上看一下它的Namspace对不对Top
24 楼liyihui2001(辉)回复于 2006-09-25 14:36:09 得分 0
不好意思,给大家说明,写的时候为了省略,就写成了MyAPP.Interface.IPlugIn,两者都是SharpMapClient.Interface.IPlugIn,我添加的是同一个文件,命名空间我都改成一样的了,怎么修改都是这个错误,两个工程里的接口文件一模一样的。
大家先不要怀疑对象不正确,创建成功后,看到一切的是正确的,就是不能转换。Top
25 楼hdt(倦怠)回复于 2006-09-25 14:42:48 得分 0
跟踪一下
接口的
AssemblyQualifiedNameTop
26 楼liyihui2001(辉)回复于 2006-09-25 14:43:20 得分 0
我用的是VS2005,哪位有时间随便写个接口,写个类,编译成Dll,在另外一个程序中调用一下,应该也是这个问题。Top
27 楼liyihui2001(辉)回复于 2006-09-25 14:48:10 得分 0
type信息如下:
AssemblyQualifiedName = "SharpMapClient.Interface.Class1, ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
SharpMapClient.Interface.IPlugIn plug = (SharpMapClient.Interface.IPlugIn)obj;就错了Top
28 楼hdt(倦怠)回复于 2006-09-25 14:55:26 得分 0
把你的项目设置详细说说,我怀疑
是你引用了 SharpMapClient.Interface 这个dll,再用Assembly.load 这个dll,出现的问题
Top
29 楼Knight94(愚翁)回复于 2006-09-25 15:06:37 得分 40
to 不好意思,给大家说明,写的时候为了省略,就写成了MyAPP.Interface.IPlugIn,两者都是 SharpMapClient.Interface.IPlugIn,我添加的是同一个文件,命名空间我都改成一样的了,怎么修改都是这个错误,两个工程里的接口文件一模一样的。
即使定义完全一样,都是通过同一个文件产生的,但是在不同项目中编译后,就属于不同的类型。
Top
30 楼Knight94(愚翁)回复于 2006-09-25 15:10:24 得分 0
那么正确的调用方式应该如下:
//dll file
using System;
namespace InterfaceTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class clsTest:IDisplayName
{
public clsTest()
{
//
// TODO: Add constructor logic here
//
}
#region IDisplayName Members
public string GetName()
{
// TODO: Add clsTest.GetName implementation
return "hello world";
}
#endregion
}
public interface IDisplayName
{
string GetName();
}
}
//程序中调用如下:
Assembly ass = Assembly.LoadFile( yourDllFile );
Type typClass = ass.GetType( "InterfaceTest.clsTest" );
object obj = typClass.InvokeMember(
null,
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.CreateInstance,
null,
null,
null );
Type typInterface = typClass.GetInterface( "InterfaceTest.IDisplayName" );
MethodInfo mi = typInterface.GetMethod( "GetName" );
if( mi != null )
Debug.WriteLine( mi.Invoke( obj, null ).ToString() );
Top
31 楼liyihui2001(辉)回复于 2006-09-25 15:12:34 得分 0
多谢Knight94(愚翁),Knight94(愚翁)的解释是正确的。
现在我把两个项目里面的接口文件都删除掉,重新建立了一个工程,把两个接口文件都加进去,编译成接口只包含两个接口的Dll,我的程序工程和接口类工程都对这个Dll进行引用,转换没有问题。
即使定义完全一样,都是通过同一个文件产生的,但是在不同项目中编译后,就属于不同的类型。(这句最重要,呵呵)
再次多谢各位。Top
32 楼yzx110(原振侠)回复于 2006-09-25 16:04:24 得分 0
lz的代码算是一个繁琐的做法
你直接配置实现了IPlugIn借口的类型
比如type="ClassLibrary.Class1, ClassLibrary";
代码中调用 Type t = Type.GetType(type);
if ( t == null) // process the exception
然后 IPlugIn p = (IPlugIn)Activator.CreateInstance(t);Top
33 楼yzqlee()回复于 2006-09-25 16:18:06 得分 0
upTop
34 楼liyihui2001(辉)回复于 2006-09-25 17:42:46 得分 0
呵呵,从IPlugIn派生的类我可不知道,谁都可以写个类,只要放到指定的地方,我程序运行时才加载的,何来类名字?
麻烦也只能这样了。Top
35 楼szh3210(/+/=〆)回复于 2006-09-26 10:14:00 得分 0
markTop




