Como posso descobrir o “caminho” de um recurso incorporado?

110

Estou armazenando um PNG como um recurso incorporado em um assembly. Dentro da mesma montagem, tenho alguns códigos como este:

Bitmap image = new Bitmap(typeof(MyClass), "Resources.file.png");

O arquivo, denominado "file.png", é armazenado na pasta "Recursos" (no Visual Studio) e é marcado como um recurso incorporado.

O código falha com uma exceção dizendo:

O recurso MyNamespace.Resources.file.png não pode ser encontrado na classe MyNamespace.MyClass

Eu tenho um código idêntico (em uma montagem diferente, carregando um recurso diferente) que funciona. Portanto, sei que a técnica é sólida. Meu problema é que acabo gastando muito tempo tentando descobrir qual é o caminho correto. Se eu pudesse simplesmente consultar (por exemplo, no depurador) o assembly para encontrar o caminho correto, isso me pouparia um monte de dores de cabeça.

Roubar
fonte

Respostas:

198

Isso fornecerá a você uma matriz de string de todos os recursos:

System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
John
fonte
3
Ei, como posso obter o caminho da pasta de recursos para atribuí-lo como o diretório raiz para meu servidor http incorporado?
lazzy_ms
45

Eu me pego me esquecendo de como fazer isso todas as vezes, então eu apenas envolvo as duas linhas que preciso em uma pequena aula:

public class Utility
{
    /// <summary>
    /// Takes the full name of a resource and loads it in to a stream.
    /// </summary>
    /// <param name="resourceName">Assuming an embedded resource is a file
    /// called info.png and is located in a folder called Resources, it
    /// will be compiled in to the assembly with this fully qualified
    /// name: Full.Assembly.Name.Resources.info.png. That is the string
    /// that you should pass to this method.</param>
    /// <returns></returns>
    public static Stream GetEmbeddedResourceStream(string resourceName)
    {
        return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
    }

    /// <summary>
    /// Get the list of all emdedded resources in the assembly.
    /// </summary>
    /// <returns>An array of fully qualified resource names</returns>
    public static string[] GetEmbeddedResourceNames()
    {
        return Assembly.GetExecutingAssembly().GetManifestResourceNames();
    }
}
Dylan
fonte
19

Suponho que sua classe esteja em um namespace diferente. A maneira canônica de resolver isso seria usar a classe de recursos e um recurso fortemente tipado:

ProjectNamespace.Properties.Resources.file

Use o gerenciador de recursos do IDE para adicionar recursos.

Konrad Rudolph
fonte
Você está certo, minha classe está em um namespace diferente. Parece que a pasta Resources reside no namespace especificado como o namespace padrão na configuração do projeto, que por vários motivos não é o namespace do qual essa classe faz parte. Suspeito que você também esteja certo sobre usar uma abordagem totalmente diferente, mas como preciso ser consistente com o código legado, isso está além do meu controle.
Rob
7
Isso captura o recurso - não o caminho do arquivo.
Uchiha Itachi
3
@UchihaItachi É por isso que ofereci esta resposta explicitamente como outra (e indiscutivelmente canônica) maneira de resolver o problema subjacente, em vez de responder à pergunta literalmente (que já tem uma resposta de qualquer maneira).
Konrad Rudolph
1
@UchihaItachi A pergunta também informa o problema que a pessoa que pergunta está enfrentando, qual é a abordagem dele e como ela tentou até agora. Embora Rudolph não responda diretamente à pergunta, ele aborda outra abordagem para resolver o problema. Na maioria dos casos, essa abordagem é mais conveniente, segura e comum. Essa resposta é útil. Só não entendo por que você tem que tentar bloquear as respostas das pessoas. Os botões Vote Up / Vote Down existem por uma razão.
Nin,
5

Eu uso o seguinte método para obter recursos incorporados:

    protected static Stream GetResourceStream(string resourcePath)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        List<string> resourceNames = new List<string>(assembly.GetManifestResourceNames());

        resourcePath = resourcePath.Replace(@"/", ".");
        resourcePath = resourceNames.FirstOrDefault(r => r.Contains(resourcePath));

        if (resourcePath == null)
            throw new FileNotFoundException("Resource not found");

        return assembly.GetManifestResourceStream(resourcePath);
    }

Em seguida, chamo isso com o caminho no projeto:

GetResourceStream(@"DirectoryPathInLibrary/Filename")
masterwok
fonte
3

O nome do recurso é o namespace mais o "pseudo" namespace do caminho para o arquivo. O espaço de nome "pseudo" é criado pela estrutura de subpasta usando \ (barras invertidas) em vez de. (pontos).

public static Stream GetResourceFileStream(String nameSpace, String filePath)
{
    String pseduoName = filePath.Replace('\\', '.');
    Assembly assembly = Assembly.GetExecutingAssembly();
    return assembly.GetManifestResourceStream(nameSpace + "." + pseduoName);
}

A seguinte chamada:

GetResourceFileStream("my.namespace", "resources\\xml\\my.xml")

retornará o fluxo de my.xml localizado na estrutura de pastas resources \ xml no espaço de nomes: my.namespace.

user3356450
fonte
6
Além disso, travessões ('-') nas pastas são substituídos por sublinhados ('_'). Pode haver outros símbolos também. Eu gostaria de ver como o compilador está fazendo isso para que possamos usar o mesmo método.
Boyko Karadzhov