IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Compilation de code à la volée


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2010
    Messages : 188
    Par défaut Compilation de code à la volée
    Bonjour,
    J'ai 2 questions pour le prix d'une.



    Environnement :
    • Windows 10
    • Visual Studio 2019 Community
    • Framework 4.8
    • C# 8


    A noter que le code est réduit à l'essentiel et que les chemins donnés sont réduits également.

    Ce que je fais :
    Je compile un code dynamiquement avec les outils System.CodeDom.Compiler.CodeDomProvider.CreateProvider() et System.CodeDom.Compiler.CompilerParameters().
    Pour cette compilation, je pointe des dll dont j'informe le compilateur de leur chemin d'accès (C:\MesDLLs\) qui est différent du répertoire courant de mon application (C:\MonAppli\bin\Debug\).
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CompilerParameters parameters = new CompilerParameters();
     
    parameters.ReferencedAssemblies.AddRange(ReferencedAssemblies.ToArray());

    ReferencedAssemblies est de type List<string> pour avoir toutes les DLLs souhaitées.

    La compilation se passe bien, pas d'erreur, nickel

    Maintenant, je souhaite l'exécuter avec le code suivant :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // La compilation
    CompilerResults compil= CodeDomProvider.CreateProvider("csharp").CompileAssemblyFromSource(parameters, sourceCode);
     
    // La detection d'erreur
    if (compil.Errors.HasErrors)
    {
        foreach (CompilerError item in Errors)
            Console.WriteLine(($"Ligne {item.Line} : {item.ErrorNumber} <=> '{item.ErrorText}'{(item.Line > 0 ? $" => '{sourceCode.Split('\n')[item.Line - 1].Trim()}'" : string.Empty)}");
     
     
        throw new Exception($"Au moins une erreur de compilation est survenu pour '{className}'.");
    }
     
    // L'exécution
    compil.CompiledAssembly.GetType("MonType").GetMethod("MaMethode").Invoke(obj, parameters);
    Et là ça crache, avec le message d'erreur suivant :

    Message d'erreur => Une exception a été levée par la cible d'un appel.

    Message d'erreur dans le InnerException => Impossible de charger le fichier ou l'assembly 'MaDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' ou une de ses dépendances. Le fichier spécifié est introuvable.

    Et particularité de System.Reflexion.TargetInvolationException, j'ai une propriété FusionLog qui me donne tout ça =>
    === Informations d'état de liaison préalable ===
    JRN*: DisplayName = MaDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    (Fully-specified)
    JRN*: Appbase = file:///C:/MonAppli/bin/Debug/
    JRN*: PrivatePath initial = NULL
    Assembly appelant*: (Unknown).
    ===
    JRN*: cette liaison démarre dans le contexte de chargement de default.
    JRN*: utilisation du fichier de configuration de l'application*: C:\MonAppli\bin\Debug\MonAppli.exe.Config
    JRN*: utilisation du fichier de configuration d'hôte*:
    JRN*: utilisation du fichier de configuration de l'ordinateur à partir de C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
    JRN*: stratégie non appliquée à la référence à ce stade (liaison d'assembly privée, personnalisée, partielle ou basée sur l'emplacement).
    JRN*: tentative de téléchargement de la nouvelle URL file:///C:/MonAppli/bin/Debug/MaDLL.DLL.
    JRN*: tentative de téléchargement de la nouvelle URL file:///C:/MonAppli/bin/Debug/MaDLL/MaDLL.DLL.
    JRN*: tentative de téléchargement de la nouvelle URL file:///C:/MonAppli/bin/Debug/MaDLL.EXE.
    JRN*: tentative de téléchargement de la nouvelle URL file:///C:/MonAppli/bin/Debug/MaDLL/MaDLL.EXE.
    (Bien sûr, MonType et MaMethode n'ont pas d'erreur de frappe et existe bien dans le code fraîchement compilé)

    Première question :
    Pourquoi la compilation OK mais pas l'exécution ?



    Après quelques heures (jours) à chercher, je teste ceci :
    Je copie manuellement mes DLLs dans le répertoire C:/MonAppli/bin/Debug/ => Et là ça fonctionne

    Je peux aussi ajouter une référence à ces DLLs depuis mon projet MonAppli mais cela ne me convient pas car ce sont des DLLs également compilées à la volée au début de l'exécution du programme et je ne les connais pas à l'avance (officiellement).

    Première question subsidiaire :
    Comment dire à mon projet d'aller voir également le répertoire C:\MesDLLS\ ?
    J'ai essayé en ajoutant le chemin dans les chemins d'accès des références dans la fenêtre des propriétés du projet, cela n'a pas fonctionné
    J'ai essayé en l'ajoutant au PATH système de windows pour l'ajouter, cela n'a pas fonctionné non plus...

    Seconde question :
    Dans le code, j'ai
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int a = 1; Console.WriteLine(a.ToString("00"))
    Que j'ai transformé en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int a = 1; Console.WriteLine($"{a:00}"))
    Et là, à la compilation, j'ai cette erreur :
    Ligne 12 : CS1056 <=> 'Caractère '$' inattendu' => 'int a = 1; Console.WriteLine($"{a:00}");'
    Je n'ai pas envie de revenir au .ToString("00"), on se fait vite au sucre syntaxique... Et surtout, il y en a partout... Comment résoudre ce problème ?

    Voilà, merci d'avoir lu mes questions, et encore plus d'y répondre ou de donner des pistes de recherche pour y répondre.

  2. #2
    Membre Expert
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Billets dans le blog
    7
    Par défaut
    Bonjour,

    Pour ta première question, lors de l'exécution d'une assembly primaire (.exe) la recherche des références s'effectue dans des répertoires spécifiques comme tu auras pu le remarquer une référence côte à côte est de suite trouvée.
    Si tu veux cibler un autre répertoire de recherche (ex : C:\) il faut le prévoir dans ton binaire grâce à l’événement "ResolveEventHandler". Exemple ici :
    https://stackoverflow.com/questions/...runtime-in-net

    Bon codage++

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2010
    Messages : 188
    Par défaut Super, reste la seconde question...
    Salut Wallace1,
    Merci pour ta réponse, elle donne effectivement une bonne piste et après avoir bidouillé un petit quelque chose avec au niveau de mon projet, ça fonctionne.

    Maintenant je vais voir si là où je l'ai mis est le plus pertinent ou s'il aurait plus sa place ailleurs (ça dépend surtout de la structure de ma solution donc je ne rentre pas dans les détail ici).

    Reste la seconde question à propos du sucre syntaxique, des idées à propos de ce $ ?

  4. #4
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2010
    Messages : 188
    Par défaut Ce n'est pas dans la question initiale mais...
    Je continue mes tests et je découvre un problème similaire à ma question 2 à propos du $...

    Lorsque j'écris le code suivant :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    var a = MonObjet?.MaPropriete;
    , contraction de
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    var a = null; if (MonObjet != null) a = MonObjet.MaPropriete;
    J'ai 3 erreurs d'un coup :
    Ligne 25 : CS1525 <=> 'Terme d'expression non valide '.'' => 'var a = MonObjet?.MaPropriete;'
    Ligne 25 : CS1003 <=> 'Erreur de syntaxe, ':' attendu' => 'var a = MonObjet?.MaPropriete;'
    Ligne 25 : CS1002 <=> '; attendu' => 'var a = MonObjet?.MaPropriete;'
    Des idées ?

  5. #5
    Membre Expert
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Billets dans le blog
    7
    Par défaut
    RE, je n'ai pas eu le temps de répondre à ta 2ème question tout à l'heure.....

    Je ne sais pas si codedom prends vraiment en compte ce type de raccourci syntaxique mais j'ai tout de même une question :

    As-tu essayés de déclarer la version de ton cscodeprovider (lié à la version du Framework) ?

    Exemple très succint :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var Version = new Dictionary<string, string>() { { "CompilerVersion", "4.8"} };
    CSCodeProvider cProv = new CSCodeProvider(Version);
    CompilerParameters cParams = new CompilerParameters();
    ....
    ........
    ++

  6. #6
    Membre confirmé
    Homme Profil pro
    Ingénieur Informatique
    Inscrit en
    Décembre 2005
    Messages
    146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur Informatique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 146
    Par défaut
    Je pense surtout que c'est lié à la version du language c# qui n'est plus piloté par la version du Framework à présent.
    de mémoire il faut s'appuyer sur le package Microsoft.CodeDom.Providers.DotnetCompilerPlatform pour parvenir à compiler une version plus récente du C# via CSCodeProvider.

  7. #7
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    Citation Envoyé par ypelissier Voir le message
    Je continue mes tests et je découvre un problème similaire à ma question 2 à propos du $...

    Lorsque j'écris le code suivant :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    var a = MonObjet?.MaPropriete;
    , contraction de
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    var a = null; if (MonObjet != null) a = MonObjet.MaPropriete;
    J'ai 3 erreurs d'un coup :


    Des idées ?
    Pour la version de System.CodeDom plus récente il y a celle -là à voir :
    System.CodeDom version="4.7.0" targetFramework="net461" de nov.2019
    la même revue mais à des dates postérieure à nov.2019 .

    Sous forme de package nuget sur ce lien:
    https://www.nuget.org/packages/System.CodeDom/


    Quant à l'operateur ternaire ? c'est du "syntaxic sugar" et dans le CodeDom sa construction syntaxique de base est simplement un "if/else".
    bon code.

  8. #8
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2010
    Messages : 188
    Par défaut
    Bonjour,
    @MABROUKI : A la base, avant de télécharger le nuget package dont tu me parles, quand j'utilise CodeDomProvider, Visual Studio me suggère d'utiliser using System.CodeDom.Compiler;.
    Lorsque je vais voir la référence de CodeDomProvider, je peux voir que System.CodeDom.Compiler se trouve dans la DLL System.dll
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #region assembly System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    // C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.dll
    #endregion

    Après l'avoir référencé (le nuget package), lorsque je fais la même opération, en ayant pris soin de retirer le using, VS ne me propose pas d'autres alternatives que de me faire pointer sur System.CodeDom.Compiler . Comment pointer sur le package nouvellement référencé ?

    @Tous :
    J'ai fait un micro-projet pour pouvoir le tester :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    using System;
    using System.CodeDom.Compiler;
     
    namespace CompilationALaVolee
    {
        class Program
        {
            static void Main(string[] args)
            {
                var sourceCode = "using System;\r\n" +
                "namespace TestNamespace\r\n" +
                "{\r\n" +
                    "\tpublic static class TestClass\r\n" +
                    "\t{\r\n" +
                        "\t\tpublic static void TestMethod()\r\n" +
                        "\t\t{\r\n" +
                            "\t\t\tint? i = 5;\r\n" +
                            "\t\t\tConsole.WriteLine($\"Test {i}\");\r\n" + // Pour tester le $""
                            //"\t\t\tConsole.WriteLine(\"Test \" + i?.ToString());\r\n" + // Pour tester le ?.
                        "\t\t}\r\n" +
                    "\t}\r\n" +
                "}\r\n";
     
                CompilerParameters parameters = new CompilerParameters();
     
                parameters.ReferencedAssemblies.Add("System.dll");
                parameters.OutputAssembly = "Test.dll";
                parameters.CompilerOptions = "/t:library";
                parameters.GenerateInMemory = false;
                parameters.GenerateExecutable = false;
                parameters.IncludeDebugInformation = false;
     
                var results = CodeDomProvider.CreateProvider("csharp"
                                                            //, new Dictionary<string, string> { { "CompilerVersion", "4.8"} } // Si ligne présente alors => System.InvalidOperationException*: 'Le fichier exécutable du compilateur csc.exe est introuvable.'
                                                            ).CompileAssemblyFromSource(parameters, sourceCode);
     
                if (results.Errors.HasErrors)
                    foreach (CompilerError item in results.Errors)
                        Console.WriteLine(item.ErrorNumber + " <=> " + item.ErrorText);
                else
                    results.CompiledAssembly.GetType("TestNamespace.TestClass")
                                            .GetMethod("TestMethod")
                                            .Invoke(null, null);
     
                Console.ReadLine();
            }
        }
    }

    Si installation de Microsoft.CodeDom.Providers.DotNetCompilerPlatform => // System.InvalidOperationException*: 'Le fichier exécutable du compilateur csc.exe est introuvable.', comme pour l'indication de la version du compilateur
    Si installation de Microsoft.CodeDom.Providers.DotNetCompilerPlatform.BinFix => CS1617 Invalid option 'preview' for /langversion; must be ISO-1, ISO-2, Default or an integer in range 1 to 6.

    Contenu du fichier Directory.Build.props
    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <Project>
     <PropertyGroup>
       <LangVersion>preview</LangVersion>
     </PropertyGroup>
    </Project>

    Si changement de version pour la 6 (pas souhaité, je veux bien redescendre en 8.0 mais pas en 6), retour au point de départ => CS1056 <=> Caractère '$' inattendu...

    J'ai comme qui dirait l'impression de tourner en rond...

    Quelqu'un aurait-il une autre proposition ou un élément complémentaire à me proposer ?

    Merci beaucoup

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. compilation de code source
    Par lejum dans le forum Général Java
    Réponses: 11
    Dernier message: 20/03/2006, 20h13
  2. Compiler du code Java via Java
    Par sozie9372 dans le forum Langage
    Réponses: 2
    Dernier message: 12/01/2006, 10h14
  3. Probleme en compilant le code avec C2.EXE ?!?!?
    Par angelevil dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 17/11/2005, 16h13
  4. [Servlet][Compilation] Erreur de compil dans code servlet
    Par gandalf_le_blanc dans le forum Servlets/JSP
    Réponses: 3
    Dernier message: 13/05/2004, 10h17
  5. Compiler un code sous windows
    Par KORTA dans le forum Choisir un environnement de développement
    Réponses: 2
    Dernier message: 30/09/2003, 16h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo