创新构筑未来,团队创造奇迹

挖掘互联网的长尾潜力……(欢迎访问:老高的博客)
数据加载中……
用.net动态创建类的实例

        看了网上很多关于DotNet动态创建类的实例的文章,我这里想总结一下,其实方法很简单,就是用“Activator.CreateInstance”。但是这个方法需要待创建的类的Type作为参数,为了获得该参数,可以利用[Assembly].GetType方法,这个方法只需要待创建的类的名称(名称字符串)就可以了,最后的问题就是要获得这个类所在的程序集。如何获得待创建的类所在程序集,那么就解决了这个问题。
        大家可以参考http://www.cnblogs.com/ShadowK/archive/2006/11/14/560131.html,费了很多笔墨写了一个比较完整的动态构造类的设计器。其实,在获得程序集这个问题上,可以有更简单的办法,以下是我的做法。
        利用Microsoft.VisualBasic.VBCodeProvider(),如果是C#可以用CSharpCodeProvider(),将类文件编译成为DLL文件,然后利用[Assembly].LoadFrom("DLL 的绝对路径")加载该DLL。这样我们可以避免在那些创建DLL和Type的复杂代码。我告诉我的项目组成员这个例子后,强调要打开思路,Simple is perfect,凡事都尽量找简便的方法来实现,客户永远不会为我们那些复杂的代码多花一分钱。
1.执行编译任务的方法:

    Public Shared Function CompileExecutable(ByVal sourceName As StringByVal DLLPath As StringByRef ReturnDLLName As StringAs Boolean
        
Dim sourceFile As FileInfo = New FileInfo(sourceName)
        
Dim provider As CodeDomProvider = Nothing
        
Dim compileOk As Boolean = False

        
' 根据原文件的扩展名选择code provider
        If sourceFile.Extension.ToUpper(CultureInfo.InvariantCulture) = ".CS" Then

            provider 
= New Microsoft.CSharp.CSharpCodeProvider()

        
ElseIf sourceFile.Extension.ToUpper(CultureInfo.InvariantCulture) = ".VB" Then

            provider 
= New Microsoft.VisualBasic.VBCodeProvider()

        
Else
            Console.WriteLine(
"原文件必须包含 .cs 或 .vb 扩展名")
        
End If

        
If Not provider Is Nothing Then

            
' 构造DLL文件的全路径
            Dim dllName As String = String.Format("{0}\{1}.dll", _
                DLLPath, _
                sourceFile.Name.Replace(
".""_"))

            ReturnDLLName 
= dllName

            
Dim cp As CompilerParameters = New CompilerParameters()

            
' 设置编译控制参数
            cp.GenerateExecutable = False '生成DLL,如果是True则生成exe文件
            cp.OutputAssembly = dllName
            cp.GenerateInMemory 
= False
            cp.TreatWarningsAsErrors 
= False

            
' 调用编译方法将原代码文件编译成DLL
            Dim cr As CompilerResults = provider.CompileAssemblyFromFile(cp, _
                sourceName)

            
If cr.Errors.Count > 0 Then
                
' 显示编译错误
                Console.WriteLine("编译错误 {0} 编译成 {1}", _
                    sourceName, cr.PathToAssembly)

                
Dim ce As CompilerError
                
For Each ce In cr.Errors
                    Console.WriteLine(
"  {0}", ce.ToString())
                    Console.WriteLine()
                
Next ce
            
Else
                
' 显示编译成功的消息
                Console.WriteLine("原文件 {0} 编译成 {1} 成功完成.", _
                    sourceName, cr.PathToAssembly)
            
End If

            
' 返回编译结果
            If cr.Errors.Count > 0 Then
                compileOk 
= False
            
Else
                compileOk 
= True
            
End If
        
End If
        
Return compileOk

    
End Function


2.编译DLL,并动态创建类的实例。(这里类的原文件是Class1.vb文件,放在WebSite的App_Code文件夹中了,实际使用时可以放在任意物理位置。)

        Dim strSourceFileName As String = Server.MapPath("~/App_Code/Class1.vb"'类文件的全路径
        Dim strDllPath As String = Server.MapPath("~/App_Code"'编译后的DLL文件存放的位置
        Dim strDllName As String = "" 'DLL的全路径(返回值)
        CompileExecutable(strSourceFileName, strDllPath, strDllName) '编译原文件为DLL文件

        
Dim a As [Assembly= [Assembly].LoadFrom(strDllName) '加载DLL
        Dim myType As System.Type = a.GetType("Class1"'获得Class1的Type
        Dim obj As Object = Activator.CreateInstance(myType) '获得Class1的实例

3.Class1.vb原文件
Public Class Class1
    
Public i As Integer
End Class

posted on 2007-05-17 22:16 老高 阅读(3219) 评论(23)  编辑 收藏 所属分类: 前沿阵地

评论

#1楼  2007-05-17 22:57 Artech      

基本上动态创建对象有两种方法:
1. Reflection.
2. Deserialization.
使用的使用都应该考虑Performance。

不过这样介绍基础的文章放在首页,个人觉得欠妥:)
    回复  引用  查看    

#2楼  2007-05-17 23:04 kisskiki [未注册用户]

其实lz说的这个方法已经有人提出来过。
    回复  引用    

#3楼  2007-05-17 23:16 黄志强      

不错的文章
    回复  引用  查看    

#4楼  2007-05-18 00:16 世魁      

很好,谢谢分享

已经看过的、或觉得不值得一看的,请注意尊重他人。如果你有更好的方法或更精辟的方法,为什么没有写出来与他人共享呢?尊重别人才会得到尊重。
    回复  引用  查看    

#5楼  2007-05-18 00:18 lexus      

to Artech
楼上的水平可能太高了,像吾等菜鸟看了觉得挺好的,lz可否说一下,这个具体的应用环境,小弟初学
    回复  引用  查看    

#6楼  2007-05-18 00:50 Artech      

@世魁 and @lexus
你的话严重了。你从我的话看出了不尊重?看来我要改变我说话的方式了:)

我只想说这种基础性的东西,有专有的分区。只是建议在发布的时候做一下评估,应该放在哪里。毕竟首页是整个Cnblogs的门户。如果所有的人都不顾内容,都往上面发的话,不利于博客园的发展。

个人观点,仅当参考。
    回复  引用  查看    

#7楼  2007-05-18 01:50 丁丁      

@lexus
反射在.NET Provider设计模式(欠妥,但找不到更好的词了)中被大量使用
也正好有一个相当好的视频,就运用了.NET反射,可以看看:
http://www.dnrtv.com/default.aspx?showID=52

@artech
不是我不明白,这个世界变化快,以前被认为高级技巧的反射,现在上原创首页的确稍微有点不够份量,不过相比今天的其他首页文章,唉,反正我个人是每天cnblogs的所有区都看的
    回复  引用  查看    

#8楼  2007-05-18 08:15 布尔      

动态编译就算了吧,暂时还没有用到,反射还是很实用的。
    回复  引用  查看    

#9楼  2007-05-18 08:24 预备役中尉      

请各位大狭指点下,这个是用到企业库的builder做的.
http://www.cnblogs.com/jiangshaofen/archive/2007/05/15/747007.html已实际使用.
    回复  引用  查看    

#10楼  2007-05-18 08:30 zdq2601 [未注册用户]

基础是我们的根本
    回复  引用    

#11楼  2007-05-18 08:55 网魂小兵      

我觉得反射已经是很实用,很基本的东东了,除了那些只会拖控件的,而不写程序代码的。只要你有用到Provider的地方一般都会用到反射,性能是个很大的问题,呵呵!鄙人也写过,和这个相似的是:我想做个Web中即插即用的插件,想到了这个方法!但是是C#的内容。呵呵!
    回复  引用  查看    

#12楼 [楼主] 2007-05-18 09:13 ZhenYu      

其实反射涉及的内容很复杂,我在这里想利用动态编译DLL,结合反射动态创建类,从而获得程序上的灵活性。写这篇文章前,我参考了几乎所有Google和Baidu上利用DotNet动态创建类的文章,这里,我想把这个复杂的问题简单化,为我们实际使用提供一个方便的解决办法。
动态编译DLL可以不形成物理文件,而只生成到内存中,这样基本上没有效率方面的问题。大家有兴趣可以试试。
为什么写这篇文章呢,主要原因是:我在设计时无法确定数据类的内容,而又要用ObjectDataSource来绑定该类,并在运行时动态加载FormView的各个模板,所以才想出这个方法。实际应用后,既简单,又能解决问题,这才想拿出来和大家分享。
这两天会把FormView动态构造并绑定数据源的全过程放上来,个人认为是目前网上比较好的一个解决方法。还请大家指教。
    回复  引用  查看    

#13楼 [楼主] 2007-05-18 09:18 ZhenYu      

另外补充一点,其实在实际软件开发过程中,往往基础的概念和思想更为重要,我始终认为,内容重于形式。例如,到底选择包容还是选择聚合模式,在实际应用中就非常重要,网上目前很多关于FormView动态构造的例子都用了聚合模式——即继承模式,从基类ITemplate继承,来解决;其实,利用包容模式更好,这好比站在巨人的肩膀上,而不是什么都要自己发明创造。
总之,希望在这里和大家探讨更多解决问题的方式。
    回复  引用  查看    

#14楼  2007-05-18 09:33 YY [未注册用户]

@ZhenYu
写这篇文章前,我参考了几乎所有Google和Baidu上相关的文章

牛皮破了没有?
    回复  引用    

#15楼  2007-05-18 10:17 Klesh Wong      

@Artech
Deserialization 似乎也是利用 Reflection 来动态创建类的实例的。
    回复  引用  查看    

#16楼  2007-05-18 10:43 Artech      

@Klesh Wong
不错,要动态创建对象,必须首先知道Type的Meadata,Reflection过程是必不可少的。
    回复  引用  查看    

#17楼  2007-05-18 11:47 浪子      

“动态编译DLL可以不形成物理文件,而只生成到内存中,这样基本上没有效率方面的问题。大家有兴趣可以试试。 ”

这样的话,是否说我必须发布源码文件,否则无法动态编译。

还有多个人同时调用的时候,编译后的dll的缓存机制是?是否变成没人都需要编译一份?效率会否有问题?
    回复  引用  查看    

#18楼  2007-05-18 11:56 Vokobo      

我觉得写得不错啊。
这个思路可不可以这样:
1,我们提供一个页面定义得到我们需要编译的CS文件内容。
2,把这个放到内存里。(这点请LZ说明下怎么做)
3,动态编译一下。(请LZ把用到的类的命名空间写明一下,不是大家都知道。)
4,装载3生成的DLL。然后反射使用类的实例。

其实我对这方面也有很强烈的需求,请LZ及各位高手多多指点。

BTW:请部分朋友不要那么重的火药味。您认为小儿科的东西,对有的人来说,却正是需要的。何况LZ写得也真是很好啊。
    回复  引用  查看    

#19楼  2007-05-18 13:14 henry      

@Vokobo
有时间了解一下System.CodeDom下的东西,你的问题就能解决。
    回复  引用  查看    

#20楼  2007-05-18 18:47 hehe [未注册用户]

首页文章质量严重下降,不爽ing...
    回复  引用    

#21楼 [楼主] 2007-05-18 21:35 老高      

Class1.vb文件不用预先定义,需要的时候产生一个这样的文件放到临时文件件中,然后用上边的方法动态构造Class1对象,然后将临时产生的Class1.vb文件删除。
我是从数据库中读取Class1的各个属性,然后再按照这个思路产生Class1对象的。(属性名称和属性的值都以模板的形式保存在数据库中。)
    回复  引用  查看    

#22楼  2007-05-18 22:27 过江      

放都放上来,还是帮你顶下
    回复  引用  查看    

#23楼  2007-05-19 15:27 壁虎 [未注册用户]

什么东西应该出现在首页,我想每个可能都有不同的意见。
同一个东西,你认为这是个好东西,应该放在首页跟大家分享,
但对于另一个人来说,可能这个东西只是个小儿科,放在首页是一种资源浪费。
但是你能说这两个人中的哪个人做错了吗?
每个人都希望自己需要的东西就放在眼前。

如果你认为什么东西不该放在首页,你向dudu提或者自己有权限就把他撤下来。没有必要像吞了苍蝇似的。
    回复  引用    

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-05-18 09:34 编辑过
 
另存  打印