求助: 通过反射创建类的实例,请问,怎样释放它??

时间:2023-01-09 20:03:35
接口:

public interface ITemplate_DataChanger
{
        event EventHandler<CurValueChangedArgs> CurValueChanged;
        void myChangeMethod(string sPointName, object o);
}



类:
实现该接口, 并且在类中,有一个 BackgroundWorker , 在类的方法 myChangeMethod 中, 执行
BackgroundWorker.RunWorkerAsync(),  开始一个无限的循环,计算一些数据.


通过反射创建类实例

public ITemplate_DataChanger GetSelfDefInst(string sClsName, string sCode, object objPara)
{
            string sClassName = sClsName;
            ITemplate_DataChanger obj = null;
            Assembly asm = null;
            CompilerResults cr = ClsCodeCompiler.ComPile(sCode, false);  // 动态编译代码,
            if (cr.Errors.HasErrors)
                return null;

            try
            {
                asm = cr.CompiledAssembly;
                obj = (ITemplate_DataChanger)asm.CreateInstance(sClassName, false, BindingFlags.Default, null, objPara, null, null);                
                return obj;
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
                return null;
            }
}


然后通过接口调用类中的方法
ITemplate_DataChanger  ITest = GetSelfDefInst(.....);
ITest.myChangeMethod();

现在有一个很急的问题,  就是我怎样能够释放掉ITest ,以至于重新为ITest 赋值以后, 以前的线程能够被释放/终止..

34 个解决方案

#1


学习下!不明白

#2


交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload   方法

#3


1.如果你想保持你一直都只有一个实例对象的话,那么你可以使用单键(或者叫单例)模式来实现,比如:

 C#实现Singleton的两种方法的比较

2.如果不是第1种情况,你想知道是否放掉了你实例,那么你的可以实现实现IDisposable接口.

析构函数、finalize、dispose、close的区别以及using()的用

#4


引用 2 楼 wuyq11 的回复:
交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法


可是我是在当前域中,创建的Assembly.....请问能再讲细一吗??

应该怎样使用 AppDomain.Unload 呢?? 谢谢

#5


支持 实现实现IDisposable接口

#6


引用 3 楼 xray2005 的回复:
2.如果不是第1种情况,你想知道是否放掉了你实例,那么你的可以实现实现IDisposable接口.

析构函数、finalize、dispose、close的区别以及using()的用


请问一下, 通过反射创建的实例, 这种方法好使吗??

#7


引用 4 楼 hyblusea 的回复:
引用 2 楼 wuyq11 的回复:
交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法


可是我是在当前域中,创建的Assembly.....请问能再讲细一吗??

应该怎样使用 AppDomain.Unload 呢?? 谢谢

除了你将当前域给卸载了,这点MSDN中说的很清楚,反射加载的不能单载卸载某个类
如果你要能卸载程序集的话,单独创建一个域,用完后卸载域就行了

#8


晕,不懂,我C/C++才考虑析构呢,不知道我理解的对吗?
参考MSDN:
http://msdn.microsoft.com/zh-cn/library/66x5fx1b.aspx

#10


亲爱的美羊羊童鞋,以及如梦哥和其他高手:  

我现在重新创建一个程序域, 用于管理这些程序集

AppDomain ad = AppDomain.CreateDomain("AsmMng");
ProxyObject obj = (ProxyObject)ad. // 这里用什么方法比较合适呢??

// 这里是动态代码编译所得到的结果, 现在已经得到了一个Assembly, 而不是需要从一个文件进行加载.

#11


我这样也试过,仍然报错:

...
CompilerResults cr = ClsCodeCompiler.ComPile(sCode, false);  // 动态编译代码,
Assembly asm = cr.CompiledAssembly;

AppDomain ad = AppDomain.CreateDomain("AsmMng");
AssemblyName asmName = asm.GetName();
asm = ad.Load(aa);                      // 这里就报错


InnerException: 未能加载文件或程序集“ve0edgvc, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

Message: 未能加载文件或程序集“System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

#12


不懂,学习了

#13


不懂,帮顶下

#14


关注,期待解决方案。

#15


高手帮我想想办法吧....不然明天周未又没啦.....

#16


BackgroundWorker还保留着么?
停掉不就可以了?
直接执行CancelAsync()?

#17


你这里貌似有点胡乱。估计你也工作忙累了。
你要释放资源,这个要实现IDispose接口,主动的调用释放,或是等垃圾回收来释放。对非托管资源,实现析构函数来释放。

对于线程,当然想办法终止掉了。和你反射没关系。反射的资源就随他去吧。线程停止掉就行了。

可能我没理解你真正的问题。所以我觉得这是理所应当。说的不对的地方,你再描述一下你的问题。

#18


mark,回家慢慢看

#19


引用 17 楼 wuyazhe 的回复:
你这里貌似有点胡乱。估计你也工作忙累了。
你要释放资源,这个要实现IDispose接口,主动的调用释放,或是等垃圾回收来释放。对非托管资源,实现析构函数来释放。

对于线程,当然想办法终止掉了。和你反射没关系。反射的资源就随他去吧。线程停止掉就行了。

可能我没理解你真正的问题。所以我觉得这是理所应当。说的不对的地方,你再描述一下你的问题。


不仅仅是线程终止 ,还有其他资源都需要释放, 仅仅实现IDispose不能解决这个问题,因为不是调用完类里面的方法后就释放, 需要让这个方法里面的线程继续工作一段时间 

我看了下,要卸载Assembly确实需要在一个单独的Appdomain中加载这个Assembly,然后释放的时候,将整个Appdomain卸载..

现在的问题主要是在10楼和11楼,  怎样在另一个appdomain中,加载这个Assembly.

#20


顶,没学会

#21


你并不需要新建一个appDomain仅仅为了释放资源, 有很多方法可以用, 比如说myChangeMethod()方法调用完了后直接Dispose, 但是在dispose方法里等待线程执行完。
同步/互斥, 很容易实现的。

#22


类:
实现该接口, 并且在类中,有一个 BackgroundWorker , 在类的方法 myChangeMethod 中, 执行


在这个类中再加一个接口,IDisposable

释放这个就可以了。或者ITemplate_DataChanger直接继承IDisposable

在类的释放里写一些东东。

这样就可以了。


用这个BackgroundWorker 东东,不是明志的选择。

#23


从未考虑过如何释放 反射后的 资源,来学习下!

#24



using System;
using System.Collections.Generic;
using System.Text;
using System.Data ;
namespace Person
{
    public interface IPerson:IDisposable
    {
        DataTable fnGetAllFriends();
        string p_Name { get; set; }
        int p_Age { get; set; }
        
    }
}

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace Person
{
    public class PersonZhang:IPerson 
    {
        string _name = string.Empty;
        int _age = 0;
        DataTable _friends = null;
        #region IPerson 成员

        public System.Data.DataTable fnGetAllFriends()
        {
            return this._friends;
        }

        public string p_Name
        {
            get
            {
                return this._name;
            }
            set
            {
                this._name = value;
            }
        }

        public int p_Age
        {
            get
            {
                return this._age;
            }
            set
            {
                this._age = value;
            }
        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            this._friends.Dispose();
        }

        #endregion
    }
}







using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string path = string.Empty;
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "*.dll|*.dll";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                path = dlg.FileName;
                Assembly ass = Assembly.LoadFile(path);
                object obj = ass.CreateInstance(typeof(Person.PersonZhang).FullName, true);
                Person.IPerson ip = obj as Person.IPerson;
                if (ip != null)
                {
                    ip.Dispose();
                }
            }
        }
    }
}



#25


也是第一次写这个东东。不知道对不对。

#26


引用 24 楼 zanfeng 的回复:
C# code

using System;
using System.Collections.Generic;
using System.Text;
using System.Data ;
namespace Person
{
    public interface IPerson:IDisposable
    {
        DataTable fnGetAllFr……


确实,这是其中一种方法 , 但 ip.Dispose(); 这一句, 只是释放掉对象里面的一个变量而已,并不能使整个obj对象释放....

#27


创建:
var domain = AppDomain.CreateDomain("xxx");
var asm = domain.Load("assembly");
var object = asm.CreateInstance("type");

销毁:
AppDomain.Unload(domain);

Unload完全成功还有个前提条件,创建的object的类型必须继承自MarshalByRefObject,比如:
class objecttype : MarshalByRefObject, Ixxxx
{
}

#28


引用 27 楼 guoyichao 的回复:
创建:
var domain = AppDomain.CreateDomain("xxx");
var asm = domain.Load("assembly");
var object = asm.CreateInstance("type");

销毁:
AppDomain.Unload(domain);

Unload完全成功还有个前提条件,创建的object的类型必须继承自M……


哥, 网上都这么写的,可是能用在实际项目中吗??
我现在的代码:

foreach (AssemblyName asmName in cr.CompiledAssembly.GetReferencedAssemblies())
{
     Assembly ass = _ad.Load(asmName);
}
     Assembly ass1 = _ad.Load(cr.CompiledAssembly.GetName());    //  这一句可能有问题,因为返回值是 null

     object[] objPara = ....;// 这里是获取构造函数的参数
     object ooo = _ad.CreateInstance(cr.CompiledAssembly.FullName, _ad.FriendlyName + "." + sClassName, true, BindingFlags.Default, null, objPara, null, null, null);  // 这里就直接报错, 没找到程序集



#29


动态编译的时候编译选项GenerateInMemory=false,OutputAssembly=文件名,生成临时assembly文件不要直接创建在当前domain里,或者索性在新的domain进行动态编译。

#30


引用 29 楼 guoyichao 的回复:
动态编译的时候编译选项GenerateInMemory=false,OutputAssembly=文件名,生成临时assembly文件不要直接创建在当前domain里,或者索性在新的domain进行动态编译。


objCompilerParameters.GenerateExecutable = false;
objCompilerParameters.GenerateInMemory = true;
objCompilerParameters.OutputAssembly = "abc";

项目规定了,只能输出到内存, 所以 GenerateInMemory=true
索性在新的domain进行动态编译?这样更复杂了.. 而且我还得在主appDomain中调用 ....

#31


交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法

#32


学习了!~~~~

#33


引用 31 楼 jiuchunyoung 的回复:
交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法


哥...你这种回帖是毫无意义的....

我现在就想知道,为什么从文件加载就可以,从Assembly对象就不行呢?

#34


UPUP...

#1


学习下!不明白

#2


交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload   方法

#3


1.如果你想保持你一直都只有一个实例对象的话,那么你可以使用单键(或者叫单例)模式来实现,比如:

 C#实现Singleton的两种方法的比较

2.如果不是第1种情况,你想知道是否放掉了你实例,那么你的可以实现实现IDisposable接口.

析构函数、finalize、dispose、close的区别以及using()的用

#4


引用 2 楼 wuyq11 的回复:
交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法


可是我是在当前域中,创建的Assembly.....请问能再讲细一吗??

应该怎样使用 AppDomain.Unload 呢?? 谢谢

#5


支持 实现实现IDisposable接口

#6


引用 3 楼 xray2005 的回复:
2.如果不是第1种情况,你想知道是否放掉了你实例,那么你的可以实现实现IDisposable接口.

析构函数、finalize、dispose、close的区别以及using()的用


请问一下, 通过反射创建的实例, 这种方法好使吗??

#7


引用 4 楼 hyblusea 的回复:
引用 2 楼 wuyq11 的回复:
交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法


可是我是在当前域中,创建的Assembly.....请问能再讲细一吗??

应该怎样使用 AppDomain.Unload 呢?? 谢谢

除了你将当前域给卸载了,这点MSDN中说的很清楚,反射加载的不能单载卸载某个类
如果你要能卸载程序集的话,单独创建一个域,用完后卸载域就行了

#8


晕,不懂,我C/C++才考虑析构呢,不知道我理解的对吗?
参考MSDN:
http://msdn.microsoft.com/zh-cn/library/66x5fx1b.aspx

#9


#10


亲爱的美羊羊童鞋,以及如梦哥和其他高手:  

我现在重新创建一个程序域, 用于管理这些程序集

AppDomain ad = AppDomain.CreateDomain("AsmMng");
ProxyObject obj = (ProxyObject)ad. // 这里用什么方法比较合适呢??

// 这里是动态代码编译所得到的结果, 现在已经得到了一个Assembly, 而不是需要从一个文件进行加载.

#11


我这样也试过,仍然报错:

...
CompilerResults cr = ClsCodeCompiler.ComPile(sCode, false);  // 动态编译代码,
Assembly asm = cr.CompiledAssembly;

AppDomain ad = AppDomain.CreateDomain("AsmMng");
AssemblyName asmName = asm.GetName();
asm = ad.Load(aa);                      // 这里就报错


InnerException: 未能加载文件或程序集“ve0edgvc, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

Message: 未能加载文件或程序集“System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

#12


不懂,学习了

#13


不懂,帮顶下

#14


关注,期待解决方案。

#15


高手帮我想想办法吧....不然明天周未又没啦.....

#16


BackgroundWorker还保留着么?
停掉不就可以了?
直接执行CancelAsync()?

#17


你这里貌似有点胡乱。估计你也工作忙累了。
你要释放资源,这个要实现IDispose接口,主动的调用释放,或是等垃圾回收来释放。对非托管资源,实现析构函数来释放。

对于线程,当然想办法终止掉了。和你反射没关系。反射的资源就随他去吧。线程停止掉就行了。

可能我没理解你真正的问题。所以我觉得这是理所应当。说的不对的地方,你再描述一下你的问题。

#18


mark,回家慢慢看

#19


引用 17 楼 wuyazhe 的回复:
你这里貌似有点胡乱。估计你也工作忙累了。
你要释放资源,这个要实现IDispose接口,主动的调用释放,或是等垃圾回收来释放。对非托管资源,实现析构函数来释放。

对于线程,当然想办法终止掉了。和你反射没关系。反射的资源就随他去吧。线程停止掉就行了。

可能我没理解你真正的问题。所以我觉得这是理所应当。说的不对的地方,你再描述一下你的问题。


不仅仅是线程终止 ,还有其他资源都需要释放, 仅仅实现IDispose不能解决这个问题,因为不是调用完类里面的方法后就释放, 需要让这个方法里面的线程继续工作一段时间 

我看了下,要卸载Assembly确实需要在一个单独的Appdomain中加载这个Assembly,然后释放的时候,将整个Appdomain卸载..

现在的问题主要是在10楼和11楼,  怎样在另一个appdomain中,加载这个Assembly.

#20


顶,没学会

#21


你并不需要新建一个appDomain仅仅为了释放资源, 有很多方法可以用, 比如说myChangeMethod()方法调用完了后直接Dispose, 但是在dispose方法里等待线程执行完。
同步/互斥, 很容易实现的。

#22


类:
实现该接口, 并且在类中,有一个 BackgroundWorker , 在类的方法 myChangeMethod 中, 执行


在这个类中再加一个接口,IDisposable

释放这个就可以了。或者ITemplate_DataChanger直接继承IDisposable

在类的释放里写一些东东。

这样就可以了。


用这个BackgroundWorker 东东,不是明志的选择。

#23


从未考虑过如何释放 反射后的 资源,来学习下!

#24



using System;
using System.Collections.Generic;
using System.Text;
using System.Data ;
namespace Person
{
    public interface IPerson:IDisposable
    {
        DataTable fnGetAllFriends();
        string p_Name { get; set; }
        int p_Age { get; set; }
        
    }
}

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace Person
{
    public class PersonZhang:IPerson 
    {
        string _name = string.Empty;
        int _age = 0;
        DataTable _friends = null;
        #region IPerson 成员

        public System.Data.DataTable fnGetAllFriends()
        {
            return this._friends;
        }

        public string p_Name
        {
            get
            {
                return this._name;
            }
            set
            {
                this._name = value;
            }
        }

        public int p_Age
        {
            get
            {
                return this._age;
            }
            set
            {
                this._age = value;
            }
        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            this._friends.Dispose();
        }

        #endregion
    }
}







using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string path = string.Empty;
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "*.dll|*.dll";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                path = dlg.FileName;
                Assembly ass = Assembly.LoadFile(path);
                object obj = ass.CreateInstance(typeof(Person.PersonZhang).FullName, true);
                Person.IPerson ip = obj as Person.IPerson;
                if (ip != null)
                {
                    ip.Dispose();
                }
            }
        }
    }
}



#25


也是第一次写这个东东。不知道对不对。

#26


引用 24 楼 zanfeng 的回复:
C# code

using System;
using System.Collections.Generic;
using System.Text;
using System.Data ;
namespace Person
{
    public interface IPerson:IDisposable
    {
        DataTable fnGetAllFr……


确实,这是其中一种方法 , 但 ip.Dispose(); 这一句, 只是释放掉对象里面的一个变量而已,并不能使整个obj对象释放....

#27


创建:
var domain = AppDomain.CreateDomain("xxx");
var asm = domain.Load("assembly");
var object = asm.CreateInstance("type");

销毁:
AppDomain.Unload(domain);

Unload完全成功还有个前提条件,创建的object的类型必须继承自MarshalByRefObject,比如:
class objecttype : MarshalByRefObject, Ixxxx
{
}

#28


引用 27 楼 guoyichao 的回复:
创建:
var domain = AppDomain.CreateDomain("xxx");
var asm = domain.Load("assembly");
var object = asm.CreateInstance("type");

销毁:
AppDomain.Unload(domain);

Unload完全成功还有个前提条件,创建的object的类型必须继承自M……


哥, 网上都这么写的,可是能用在实际项目中吗??
我现在的代码:

foreach (AssemblyName asmName in cr.CompiledAssembly.GetReferencedAssemblies())
{
     Assembly ass = _ad.Load(asmName);
}
     Assembly ass1 = _ad.Load(cr.CompiledAssembly.GetName());    //  这一句可能有问题,因为返回值是 null

     object[] objPara = ....;// 这里是获取构造函数的参数
     object ooo = _ad.CreateInstance(cr.CompiledAssembly.FullName, _ad.FriendlyName + "." + sClassName, true, BindingFlags.Default, null, objPara, null, null, null);  // 这里就直接报错, 没找到程序集



#29


动态编译的时候编译选项GenerateInMemory=false,OutputAssembly=文件名,生成临时assembly文件不要直接创建在当前domain里,或者索性在新的domain进行动态编译。

#30


引用 29 楼 guoyichao 的回复:
动态编译的时候编译选项GenerateInMemory=false,OutputAssembly=文件名,生成临时assembly文件不要直接创建在当前domain里,或者索性在新的domain进行动态编译。


objCompilerParameters.GenerateExecutable = false;
objCompilerParameters.GenerateInMemory = true;
objCompilerParameters.OutputAssembly = "abc";

项目规定了,只能输出到内存, 所以 GenerateInMemory=true
索性在新的domain进行动态编译?这样更复杂了.. 而且我还得在主appDomain中调用 ....

#31


交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法

#32


学习了!~~~~

#33


引用 31 楼 jiuchunyoung 的回复:
交给.Net的垃圾回收机制
释放Assembly的资源AppDomain.Unload 方法


哥...你这种回帖是毫无意义的....

我现在就想知道,为什么从文件加载就可以,从Assembly对象就不行呢?

#34


UPUP...