0

バックグラウンド:

私は XNA を使用しており、マニフェスト プロセッサを使用しています。これは、コンテンツ プロジェクト内のすべてのアセットを照合し、(とりわけ) ビルド タイプによって分類します。これを行うには、それらを構築する必要があります。これらのアセットの一部には、それ自体がマニフェストを使用するプロセッサがあります。つまり、アセット プロセッサがマニフェスト プロセッサを呼び出そうとするため、終わりのない再帰が発生します。

問題:

名前付きを使用して、プロジェクトのビルドが再帰的であることを検出し、他の場所で処理されるエラーをスローしようとしましたMutexが、機能しません。

コード:

public class ManifestProcessor : ContentProcessor<ContentManifestAsset, ContentManifestContent>
{
    private static Mutex _LockingMutex = new Mutex(false, "ManifestProcessor");

    public override ContentManifestContent Process(ContentManifestAsset input, ContentProcessorContext context)
    {
        // If we've already locked on this object then we're doing a build as a result of building some other asset, so throw an exception
        if (!_LockingMutex.WaitOne(0))
        {
            throw new NestedManifestBuildException();
        }
        else
        {
            try
            {
                // Stuff that might cause this method to get
                // invoked again (via reflection)
            }
            finally
            {
                _LockingMutex.ReleaseMutex();
            }
        }

Mutex クラスを正しく使用していますか? Process再帰的に呼び出されたことを検出するにはどうすればよいですか?

4

1 に答える 1

0

再帰を検出するために構築されているものを追跡する方法を実装しようと思います。マニフェストは既にビルドされたアセットを集約できるため、キャッシュによってビルドのパフォーマンスも向上します。マニフェストからアセットを切り離すためにMediator パターンを使用することを検討してください。

サンプル:

public class ManifestProcessor : ContentProcessor<ContentManifestAsset, ContentManifestContent>
{
    private static readonly Dictionary<string, ContentManifestContent> BuildCache = new Dictionary<string, ContentManifestContent>();

    public override ContentManifestContent Process(ContentManifestAsset input, ContentProcessorContext context)
    {
        ContentManifestContent content;

        if(!BuildCache.TryGetValue(input.Name, out content))
        {
            VerifyStackIntegrity(context, input.Name);
            content = Build(input, context);
            BuildCache.Add(input.Name, content);
            context.BuildStack.Pop();
        }

        return content;
    }

    private static void VerifyStackIntegrity(ContentProcessorContext context, string buildStep)
    {
        if(context.BuildStack.Count(x => x == buildStep) > 1)
            throw new CircularBuildException();

        context.BuildStack.Push(buildStep);
    }

    private static ContentManifestContent Build(ContentManifestAsset input, ContentProcessorContext context)
    {
        // build steps for Manifest/Assets/Recursion
    }
}

再帰期間を防ぎたい場合、最も簡単な方法はフラグを追加することです。

public class ManifestProcessor : ContentProcessor<ContentManifestAsset, ContentManifestContent>
{
    private static bool InProgress = false;

    public override ContentManifestContent Process(ContentManifestAsset input, ContentProcessorContext context)
    {
        if(InProgress) throw new InProgressBuildException();

        InProgress = true;

        return Build(input, context);
    }

    private static ContentManifestContent Build(ContentManifestAsset input, ContentProcessorContext context)
    {
        ContentManifestContent content;
        // build steps for Manifest/Assets/Recursion
        InProgress = false;

        return content;
    }
}
于 2013-05-30T12:41:18.077 に答える