この記事は、シリアル化によってアセンブリ リゾルバー ハンドラーが再帰的に呼び出される問題を解決するのに役立ちます。
元の製品バージョン: .NET Framework 3.5 Service Pack 1、4.5
元の KB 番号: 2756498
次の例のように、 XmlSerializerAssembly
属性でマークされたクラスがあるとします。
[Serializable, XmlRoot(ElementName="Bindings", IsNullable=false), XmlSerializerAssembly(AssemblyName="Contoso.ObjectLoaders.Bindings")]
public class Bindings
{
(...)
}
生成されたアセンブリは、 bin フォルダーではなく、署名され、グローバル アセンブリ キャッシュ (GAC) に配置されます。 また、 AppDomain.AssemblyResolve
イベントのハンドラーを実装し、アセンブリ リゾルバー ハンドラー メソッドでクラスのインスタンスを次のようにシリアル化します。
private static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
// Some code here
var serializer = new XmlSerializer(typeof(Bindings));
// Some more code here
}
このシナリオでは、シリアル化によってアセンブリ リゾルバー ハンドラーが再帰的に呼び出され、スタック オーバーフローが発生する可能性があります。
この動作は仕様です。 XmlSerializerAssembly
属性を持つアセンブリは、Assembly.LoadWithPartialName(string)
と共に読み込まれ、OnResolveAssembly
ハンドラーが再度呼び出されます。
このメソッドは、アセンブリが Assembly.LoadWithPartialName(string)
によって読み込まれないようにします。
これは推奨される回避策であり、再帰に関連するすべての問題を解決します。 次の例は、この回避策の単純なコード テンプレートです。 主な考え方は、既に解決済みのアセンブリを汎用リストに追加し (スレッド セーフであるために同時実行バッグが選択されました)、アセンブリが既に解決中の場合は返します。
static ConcurrentBag<string> listOfAssemblies = new ConcurrentBag<string>();
private static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
if (listOfAssemblies.Contains(args.Name))
{
// Already resolving this assembly, return now
return null;
}
try
{
listOfAssemblies.Add(args.Name);
// Add your handler code here
}
finally
{
// Assembly was handled, remove from list
listOfAssemblies.Remove(args.Name);
}
}