9

.NET で XmlSerializer インスタンスを構築すると、指定された型をシリアル化および逆シリアル化するためのアセンブリが動的に生成されます。これは時間のかかるプロセスです。Microsoft の sgen.exe ツールを使用すると、XmlSerializer インスタンスをプリコンパイルして、動的に生成せずに後で使用できます。残念ながら、これは XmlAttributeOverrides を使用する XmlSerializer インスタンスでは不可能です。

これらの XmlSerializer インスタンスをプリコンパイルして実行時の生成を回避する方法はありますか?

4

1 に答える 1

7

Andreas さん、これは sgen ツール自体の問題ではなく、XmlSerializer の実装によるものです。

Type 引数を 1 つだけ指定してコンストラクターを使用して XmlSerializer のインスタンスを作成すると、キャッシュがチェックされ、事前に生成されたアセンブリが検索されます。ただし、コンストラクターを XmlAttributeOverrides と共に使用すると、XmlSerializer はキャッシュをチェックせず、すぐに一時アセンブリを生成します。

おそらく、これは、XmlAttributeOverrides 引数を使用して実現できるシリアライゼーション ロジックの大幅な変更によるものであり、sgen などのツールではコンパイル時に「予見」することはできません。

事前にコンパイルする必要がある場合は、[ため息] XmlAttributeOverrides を避ける必要があります。これが不可能な場合は、バックグラウンド スレッドなどで、必要な XmlSerializer インスタンスを事前に作成してみてください。

ご参考までに、既定のコンストラクターのコードを次に示します (キャッシュをチェックし、事前に生成されたアセンブリを見つけようとします)。

public XmlSerializer(Type type, string defaultNamespace)
{
    this.events = new XmlDeserializationEvents();
    if (type == null)
    {
        throw new ArgumentNullException("type");
    }
    this.mapping = GetKnownMapping(type, defaultNamespace);
    if (this.mapping != null)
    {
        this.primitiveType = type;
    }
    else
    {
        this.tempAssembly = cache[defaultNamespace, type];
        if (this.tempAssembly == null)
        {
            lock (cache)
            {
                this.tempAssembly = cache[defaultNamespace, type];
                if (this.tempAssembly == null)
                {
                    XmlSerializerImplementation implementation;
                    Assembly assembly = TempAssembly.LoadGeneratedAssembly(type, defaultNamespace, out implementation);
                    if (assembly == null)
                    {
                        this.mapping = new XmlReflectionImporter(defaultNamespace).ImportTypeMapping(type, null, defaultNamespace);
                        this.tempAssembly = GenerateTempAssembly(this.mapping, type, defaultNamespace);
                    }
                    else
                    {
                        this.mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace);
                        this.tempAssembly = new TempAssembly(new XmlMapping[] { this.mapping }, assembly, implementation);
                    }
                }
                cache.Add(defaultNamespace, type, this.tempAssembly);
            }
        }
        if (this.mapping == null)
        {
            this.mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace);
        }
    }
}

XmlAttributeOverrides で使用されるコンストラクターは次のとおりです (常にシリアル化アセンブリを生成します)。

public XmlSerializer(Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, string defaultNamespace, string location, Evidence evidence)
{
    this.events = new XmlDeserializationEvents();
    if (type == null)
    {
        throw new ArgumentNullException("type");
    }
    XmlReflectionImporter importer = new XmlReflectionImporter(overrides, defaultNamespace);
    for (int i = 0; i < extraTypes.Length; i++)
    {
        importer.IncludeType(extraTypes[i]);
    }
    this.mapping = importer.ImportTypeMapping(type, root, defaultNamespace);
    if (location != null)
    {
        this.DemandForUserLocation();
    }
    this.tempAssembly = GenerateTempAssembly(this.mapping, type, defaultNamespace, location, evidence);
}
于 2009-09-20T14:38:27.420 に答える