Comment puis-je découvrir le «chemin» d'une ressource intégrée?

110

Je stocke un PNG en tant que ressource intégrée dans un assemblage. Dans le même assemblage, j'ai du code comme celui-ci:

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

Le fichier, nommé «file.png» est stocké dans le dossier «Resources» (dans Visual Studio) et est marqué comme une ressource incorporée.

Le code échoue avec une exception disant:

La ressource MyNamespace.Resources.file.png est introuvable dans la classe MyNamespace.MyClass

J'ai un code identique (dans un assemblage différent, chargeant une ressource différente) qui fonctionne. Je sais donc que la technique est solide. Mon problème est que je finis par passer beaucoup de temps à essayer de trouver la bonne voie. Si je pouvais simplement interroger (par exemple dans le débogueur) l'assemblage pour trouver le chemin correct, cela me sauverait une charge de maux de tête.

Rob
la source

Réponses:

198

Cela vous donnera un tableau de chaînes de toutes les ressources:

System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
John
la source
3
Hé, comment puis-je obtenir le chemin du dossier de ressources pour l'attribuer en tant que répertoire racine de mon serveur http intégré?
lazzy_ms
45

Je me surprends à oublier comment faire cela à chaque fois, alors j'emballe les deux one-liners dont j'ai besoin dans un petit cours:

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
la source
19

Je suppose que votre classe est dans un espace de noms différent. La façon canonique de résoudre ce problème serait d'utiliser la classe resources et une ressource fortement typée:

ProjectNamespace.Properties.Resources.file

Utilisez le gestionnaire de ressources de l'EDI pour ajouter des ressources.

Konrad Rudolph
la source
Vous avez raison, ma classe est dans un espace de noms différent. Il semble que le dossier Resources se trouve sous l'espace de noms spécifié comme espace de noms par défaut dans la configuration du projet, qui, pour diverses raisons, n'est pas l'espace de noms dont cette classe fait partie. Je soupçonne que vous avez également raison d'utiliser une approche entièrement différente, mais comme je dois être cohérent avec le code hérité, c'est hors de mon contrôle.
Rob
7
Cela saisit la ressource - pas son chemin de fichier.
Uchiha Itachi
3
@UchihaItachi C'est pourquoi j'ai proposé cette réponse explicitement comme un autre moyen (et sans doute canonique) de résoudre le problème sous - jacent plutôt que de répondre textuellement à la question (qui a déjà une réponse en tout cas).
Konrad Rudolph
1
@UchihaItachi La question raconte également le problème auquel la personne interrogée est confrontée, quelle est son approche et comment elle a essayé jusqu'à présent. Bien que Rudolph ne réponde pas directement à la question, il aborde une autre approche pour résoudre le problème. Dans la plupart des cas, cette approche est plus pratique, sûre et courante. Cette réponse est utile. Je ne comprends tout simplement pas pourquoi vous devez essayer de fermer les réponses des gens. Les boutons Vote Up / Vote Down sont là pour une raison.
Nin
5

J'utilise la méthode suivante pour récupérer les ressources intégrées:

    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);
    }

J'appelle ensuite cela avec le chemin dans le projet:

GetResourceStream(@"DirectoryPathInLibrary/Filename")
masterwok
la source
3

Le nom de la ressource est l'espace de nom plus l'espace de nom «pseudo» du chemin d'accès au fichier. L'espace de nom "pseudo" est créé par la structure du sous-dossier en utilisant \ (contre-obliques) au lieu de. (points).

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

L'appel suivant:

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

renverra le flux de my.xml situé dans la structure de dossiers resources \ xml dans l'espace de nom: my.namespace.

user3356450
la source
6
Les tirets ('-') dans les dossiers sont également remplacés par des traits de soulignement ('_'). Il peut également y avoir d'autres symboles. J'aimerais voir comment le compilateur le fait afin que nous puissions utiliser la même méthode.
Boyko Karadzhov