用.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 @ 2007-05-17 22:16 InFuture 阅读(3470) 评论(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">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提或者自己有权限就把他撤下来。没有必要像吞了苍蝇似的。




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 750687




相关文章:

相关链接: