C#反射メモリの処理分析

5322 ワード

この例では、C#反射メモリの処理を解析します.皆さんの参考にしてください.具体的な分析は以下の通りである.
この間、会社のプロジェクトの要求で、c#の反射のメカニズムを利用してクライアントフレームワークを作りました.クライアント内のすべてのモジュールは、FORM、UserControlなど、一定の形式で提供されています.する過程の中でとても簡単で楽しいです.具体的なプロセスは次のとおりです.
1.お客様のニーズの収集
2.需要を整理し、必要な文書を作成する
3.プログラムのインタフェーススタイルを議論によって大まかに得る
4.UIデザイナーによって設計された具体的なインタフェース形式
5.必要なサービスを必要に応じてカプセル化(c#のWCFサービスまたはJAVAのサービスを利用可能)
6.サービス管理フレームワークの作成
7.パッケージで使用するコントロール
8.クライアントフレームワークの作成
9.作成モジュール
10.テストのロード
上で言ったのは簡単な開発の過程で、もちろん中には多くの汗が含まれています.良いプログラムはすべて最も基本的なアンロード可能を満たして、挿入することができます.プラグインアーキテクチャです.クライアントでもサービスでもプラグイン管理が必要です.
c#クライアントフレームワークを作るとき、マイクロソフトの反射とファクトリモードのメカニズムを利用するとき、大きな問題があります.反射したDLLをメモリにロードしたときにメモリの解放ができず、プログラムを閉じたときにのみメモリの解放が行われるという大きな欠陥があります.私はネット上でも多くの解決策を探しましたが、成功できるものは一つもありません.その中で最も古典的なのはプラグインのアンインストールの方式で、この方式は私も行った実験で、一部のメモリを解放することができますが、すべてのメモリを解放することはできません.私が多くのプログラマーとこのことを話したとき、彼らはすべてを解放できると言った.しかし、あなたはそれをしても良い放出効果は得られません(私のレベルではだめかもしれません).今日はVSのメモリーのリリースに突っ込みます.VSのメモリはいずれも管理するメカニズムによってリソースの使用と解放を行い,非管理リソースに対しては構造関数と他の方法で解放することができる.反射の場合、マイクロソフトは良い方法を与えていません.プログラマーの兄弟たちが私たちに良い方法を提供してくれれば、それは大きな善果になります.
プラグインをアンインストールすることでメモリの一部を解放でき、効果もまあまあですが、WCFサービスで書かれたコントロールの中には、リモートモードで問題があります.具体的な実装コードは次のとおりです.

   internal class AssemblyLoader : MarshalByRefObject, IDisposable 
  
{
#region class-level declarations
private Assembly a = null;
#endregion


#region constructors and destructors
public AssemblyLoader(string fullPath)
{
if (a == null)
{
a = Assembly.LoadFrom(fullPath);
}
}


~AssemblyLoader()
{
dispose(false);
}


public void Dispose()
{
dispose(true);
}


private void dispose(bool disposing)
{
if (disposing)
{
a = null;
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect(0);
}
}
#endregion
#region public functionality
public object GetObject(string typename, object[] ctorParms)
{
BindingFlags flags = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;


object o = null
;
if (a != null)
{
try
{
o = a.CreateInstance(typename, true, flags, null, ctorParms, null, null);
}
catch
{
}
}
return o;
}


public object GetObject(string typename)
{
return GetObject(typename, null);
}
#endregion

 

public class ObjectLoader : IDisposable
{
// essentially creates a parallel-hash pair setup
// one appDomain per loader
protected Hashtable domains = new Hashtable();
// one loader per assembly DLL
protected Hashtable loaders = new Hashtable();


public ObjectLoader()
{}


public object GetObject(string dllName, string typeName, object[] constructorParms)
{
AssemblyLoader al = null;
object o = null;
//Type t = null;
try
{
al = (AssemblyLoader)loaders[dllName];
}
catch (Exception) { }


if (al == null)
{
AppDomainSetup setup = new AppDomainSetup();
setup.ShadowCopyFiles = "true";
AppDomain domain = AppDomain.CreateDomain(dllName, null, setup);
int key=0;
foreach (DictionaryEntry de in domains)
{
if(de.Key.ToString()==dllName)
{
key++;
break;
}
}
if (key == 0)
{
domains.Add(dllName, domain);
}
object[] parms = { dllName };
BindingFlags bindings = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;
try
{
//al = (BCFrameWork.Client.ClientInfrm.AssemblyLoader)domain.CreateInstanceFromAndUnwrap(
// "Loader.dll", "Loader.AssemblyLoader", true, bindings, null, parms, null, null, null);
al = (AssemblyLoader)domain.CreateInstanceFromAndUnwrap(
"BestelLoadDll.dll", "BestelLoadDll.AssemblyLoader", true, bindings, null, parms, null, null, null);
}
catch
{
}
if (al != null)
{
if (!loaders.ContainsKey(dllName))
{
loaders.Add(dllName, al);
}
}
}


if (al != null)
{
o = al.GetObject(typeName, constructorParms);

}
return o;
}


public void Unload(string dllName)
{
if (domains.ContainsKey(dllName))
{
AppDomain domain = (AppDomain)domains[dllName];
AppDomain.Unload(domain);
domains.Remove(dllName);
}
}


~ObjectLoader()
{
dispose(false);
}


public void Dispose()
{
dispose(true);
}


private void dispose(bool disposing)
{
if (disposing)
{
loaders.Clear();
List removeobj = new List();
foreach (object o in domains.Keys)
{
string dllName = o.ToString();
removeobj.Add(dllName);
}
foreach (string item in removeobj)
{
Unload(item);
}
domains.Clear();
System.GC.Collect();
}
}
}


呼び出し方法は簡単です.反射を知っていれば呼び出す方法がわかります.この書き方は、通常のユーザーコントロールの反射リモートロードを満たすことができますが、特殊なユーザーコントロールでは仕方がありません.
本稿で述べたことが皆さんのC#プログラム設計に役立つことを願っています.