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

我会尝试实现一种方法来跟踪正在构建的内容以检测递归。缓存也将提高构建性能,因为 Manifest 可以聚合已经构建的资产。研究使用中介者模式将资产​​与清单分离。

样本:

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 回答