Определить, существует ли ресурс WPF на основе URI

Учитывая URI пакета://, какой лучший способ сказать, действительно ли скомпилированный ресурс (например, PNG-образ, скомпилированный с помощью действия сборки "Ресурс" ) на этом URI?

После некоторого спотыкания я придумал этот код, который работает, но неуклюже:

private static bool CanLoadResource(Uri uri)
{
    try
    {
        Application.GetResourceStream(uri);
        return true;
    }
    catch (IOException)
    {
        return false;
    }
}

(Обратите внимание, что Application.GetResources документация неверна - он генерирует исключение, если ресурс не найден, вместо того, чтобы возвращать нуль, как правило, неправильно документируют документы.) (Документы были исправлены, см. комментарии ниже)

Мне не нравится ловить исключения, чтобы обнаружить ожидаемый (не исключительный) результат. И кроме того, я действительно не хочу загружать поток, я просто хочу знать, существует ли он.

Есть ли лучший способ сделать это, возможно, с API-интерфейсами более низкого уровня - в идеале, без фактической загрузки потока и не вылавливания исключения?

Ответ 1

Я нашел решение, которое я использую, которое не работает напрямую с пакетом Uri, но вместо этого ищет ресурс по пути ресурса. При этом этот пример можно было бы довольно легко модифицировать, чтобы поддерживать URI пакета, вместо этого, просто привязывая путь ресурса к концу uri, который использует Assembly для формулировки базовой части URI.

public static bool ResourceExists(string resourcePath)
{
    var assembly = Assembly.GetExecutingAssembly();

    return ResourceExists(assembly, resourcePath);
}

public static bool ResourceExists(Assembly assembly, string resourcePath)
{
    return GetResourcePaths(assembly)
        .Contains(resourcePath.ToLowerInvariant());
}

public static IEnumerable<object> GetResourcePaths(Assembly assembly)
{
    var culture = System.Threading.Thread.CurrentThread.CurrentCulture;
    var resourceName = assembly.GetName().Name + ".g";
    var resourceManager = new ResourceManager(resourceName, assembly);

    try
    {
        var resourceSet = resourceManager.GetResourceSet(culture, true, true);

        foreach(System.Collections.DictionaryEntry resource in resourceSet)
        {
            yield return resource.Key;
        }
    }
    finally
    {
        resourceManager.ReleaseAllResources();
    }
}