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#

  1. #1
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    185
    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 : 185
    Points : 167
    Points
    167
    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
    Expert confirmé
    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
    Points : 4 005
    Points
    4 005
    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 habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    185
    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 : 185
    Points : 167
    Points
    167
    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 habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    185
    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 : 185
    Points : 167
    Points
    167
    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
    Expert confirmé
    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
    Points : 4 005
    Points
    4 005
    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 habitué
    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
    Points : 158
    Points
    158
    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.
    Mon blog est sur https://arphonis.fr et bientôt d'autres fonctionnalités seront disponible dessus.

  7. #7
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    185
    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 : 185
    Points : 167
    Points
    167
    Par défaut
    @wallace1 : Cela ne fonctionne guère mieux, je dirais même plus : ca fonctionne moins bien car il me répond que "Le fichier exécutable du compilateur csc.exe est introuvable." à la compilation à la volée...
    @estacodo : J'ai du mal à comprendre comment utiliser ce nuget package, d'autant plus que je ne fais pas de dev ASP.Net.

    Après installation du nugut package, à la compilation de mon code, j'ai
    System.InvalidOperationException : Le fichier exécutable du compilateur csc.exe est introuvable.
    Après recherche, j'ai trouvé le package Microsoft.CodeDom.Providers.DotnetCompilerPlatform.BinFix spécialement pour les projet non ASP.Net et là, c'est à la compilation de mon projet que ça ne passe pas :
    CS1617 Invalid option 'preview' for /langversion; must be ISO-1, ISO-2, Default or an integer in range 1 to 6.
    En même temps, le package date de février 2016 !!! 7 et 8 sont certainement arrivé après...


    Il doit y avoir visual studio qui fait une précompilation...

  8. #8
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    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.

  9. #9
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    185
    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 : 185
    Points : 167
    Points
    167
    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

  10. #10
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    Citation Envoyé par ypelissier Voir le message

    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
    Mai non,non !!!
    En ce qui concerne le message énigmatique 'Le fichier exécutable du compilateur csc.exe est introuvable" c'est un bogue dans cette Api.
    Le chemin du compilateur Roslyn (aka csc.exe ou "roseline") ,est code en dur c.à.d. dire :
    Si ton appli de bureau est compilée dans \TonProjet\debug\bin\exemple.exe,
    le compilateur roslyn sera situé dans
    -\TonProjet\debug\bin\roslyn\csc.exe(voir dossier debug de ton projet),
    Mais le CSharpCodeProvider RESOUDRA(recherchera) csc.exe comme étant dans:
    \TonProjet\debug\bin\csc.exe.

    En raison de ce problème et de la nécessité d'appeler un programme externe pour faire
    ce qui doit être fait en cours de processus, cette API est dite "broken" ou complètement cassée.
    Le programme externe en cause c'est les lignes de code suivantes à rajouter:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
       //-------------------------------------------------
        //Set hardcoded environment variable to set the path to the library
        Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", "actual ROSLYN compiler location goes here", EnvironmentVariableTarget.Process);
        //Create compiler object
        CSharpCodeProvider compiler = new CSharpCodeProvider();
        //Clean up
        Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", null, EnvironmentVariableTarget.Process);
    Compilé dans vs 2017 .net framework version 4.7 l'exemple de code suivant compile et s'execute perfectly:

    1/ class CodeDomExample
    Code : 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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;
     
    namespace WinDotNetCompilers
    {
        class CodeDomExample
        {
     
            public static CodeCompileUnit BuildHelloWorldGraph()
            { 
                //' Create a new CodeCompileUnit to contain 
                //' the program graph.
                CodeCompileUnit compileUnit =
                    new CodeCompileUnit();
     
                //' Declare a new namespace called Samples.
                CodeNamespace samples = 
                    new CodeNamespace("Samples");
     
                //' Add the new namespace .
                compileUnit.Namespaces.Add(samples);
     
                // Add  import for the System 
                samples.Imports.Add(new CodeNamespaceImport("System"));
     
                // Declare a new type .
                CodeTypeDeclaration class1 =
                        new CodeTypeDeclaration("Class1");
     
                //' Add the new type to the namespace type collection.
                samples.Types.Add(class1);
                CodeTypeParameter parm = new CodeTypeParameter();
     
                CodeMemberField fieldInt = new CodeMemberField();
                fieldInt.Name="num";
                fieldInt.Type = new CodeTypeReference("System.Nullable<Int32>");
                fieldInt.Attributes =MemberAttributes.Private;
                class1.Members.Add(fieldInt);
     
                CodeMemberProperty property1 = new CodeMemberProperty();
                property1.Name = "Num";
                property1.Type = new CodeTypeReference("System.Nullable<Int32>");
                property1.Attributes = MemberAttributes.Final;
     
                property1.GetStatements.Add( new CodeMethodReturnStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(), fieldInt.Name)));
                property1.SetStatements.Add( new CodeAssignStatement( 
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(), fieldInt.Name), 
                        new CodePropertySetValueReferenceExpression()));
                class1.Members.Add(property1);
     
                // ici à toi d'ajouter le class Program(codeentrypoint)
                // qui teste ce class
     
                return compileUnit;
            }
            public static void GenerateCode(CodeDomProvider provider, CodeCompileUnit compileunit )
            {   
                //  Build the source file name with the appropriate
                // language extension.
                string sourceFile ;
                if  ( provider.FileExtension.StartsWith(".") )
                    sourceFile = "TestGraph" + provider.FileExtension;
                else
                    sourceFile = "TestGraph." + provider.FileExtension;
     
     
                    // Create an IndentedTextWriter, constructed with
                    // a StreamWriter to the source file.
                    IndentedTextWriter tw = new IndentedTextWriter(
                       new StreamWriter(sourceFile, false), "    ");
                    // Generate source code using the code generator.
                    provider.GenerateCodeFromCompileUnit(compileunit, tw, new CodeGeneratorOptions());
                    // Close the output file.
                    tw.Close();
            }
            public static CompilerResults CompileCode( CodeDomProvider provider, 
                                           string sourceFile,string exeFile)
            {
                    //Configure a CompilerParameters that links System.dll
                    //and produces the specified executable file.
                    string[] referenceAssemblies  = {"System.dll"};
                    CompilerParameters cp =new CompilerParameters(referenceAssemblies, exeFile, false);
     
                    //Generate an executable rather than a DLL file.
                    cp.GenerateExecutable = true;
     
                    //Invoke compilation.
                    CompilerResults cr  = 
                        provider.CompileAssemblyFromFile(cp,sourceFile);
                    //Return the results of compilation.
                    return cr;
            }
        }
    }
    2/ form user de test:
    Code : 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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
     
    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;
    namespace WinDotNetCompilers
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
     
            private void generate_button_Click(object sender, EventArgs e)
            {
                //Create CodeDomProvider
                //Set hardcoded environment variable to set the path to the library
                Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", @"C:\Users\ypelissier\Desktop\WinDotNetCompilers\bin\Debug\roslyn", EnvironmentVariableTarget.Process);
                CSharpCodeProvider provider = new CSharpCodeProvider();
                //Clean up
                Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", null, EnvironmentVariableTarget.Process);
     
     
                CodeDomExample.GenerateCode(provider, CodeDomExample.BuildHelloWorldGraph());
     
                // Build the source file name with the appropriate
                // language extension.
                string sourceFile = string.Empty;
                if (provider.FileExtension.StartsWith("."))
                    sourceFile = "TestGraph" + provider.FileExtension;
                else
                    sourceFile = "TestGraph." + provider.FileExtension;
     
     
                //' Read in the generated source file and
                //' display the source text.
                StreamReader sr = new StreamReader(sourceFile);
                textBox1.Text = sr.ReadToEnd();
                sr.Close();
            }
     
            private void compile_button_Click(object sender, EventArgs e)
            {
                //Create CodeDomProvider
     
                //Set hardcoded environment variable to set the path to the library
                  Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", @"C:\Users\ypelissier\Desktop\WinDotNetCompilers\bin\Debug\roslyn", EnvironmentVariableTarget.Process);
     
                CSharpCodeProvider provider = new CSharpCodeProvider();
                //Clean up
                Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", null, EnvironmentVariableTarget.Process);
     
     
                string sourceFile = string.Empty;
                if (provider.FileExtension.StartsWith("."))
                    sourceFile = "TestGraph" + provider.FileExtension;
                else
                    sourceFile = "TestGraph." + provider.FileExtension;
     
                CompilerResults cr =
                    CodeDomExample.CompileCode(provider, sourceFile, "TestGraph.EXE");
     
                if (cr.Errors.Count > 0)
                {
                    //Display compilation errors.
                    textBox1.Text =
                        "Errors encountered while building " +
                                sourceFile + " into " +
                                cr.PathToAssembly + ": " + Environment.NewLine;
     
     
                    foreach (CompilerError ce in cr.Errors)
                    {
                        textBox1.AppendText(ce.ToString() + Environment.NewLine);
                    }
                    run_button.Enabled = false;
                }
                else
                {
                    textBox1.Text = "Source " + sourceFile + " built into " +
                                    cr.PathToAssembly + " with no errors.";
                    run_button.Enabled = true;
                }
            }
     
            private void run_button_Click(object sender, EventArgs e)
            {
                Process.Start("TestGraph.EXE");
            }
     
     
         }
    }
    Ton code devrait compiler et s'exécuter correctement .
    bon code....

  11. #11
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2010
    Messages
    185
    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 : 185
    Points : 167
    Points
    167
    Par défaut
    Bonjour,
    Bon je sais, ça fait plus d'un an mais la direction du projet m'a demandé de ne plus investir de temps sur ce sujet et j'ai donc repérer le code qu'il ne fallait pas faire et j'ai fait avec. Pas de sucre syntaxique avec ?. ou de propriétés initialisées sans constructeur.
    Mais hier soir, en cherchant tout à fait autre chose (et étant dans des horaires personnels) je me suis dis que j'allais quand même essayer la solution qui m'était donnée ici.

    DONC CA FONCTIONNE !!!

    MERCI

    Par contre, après plusieurs essais sur du code, je n'ai pas tout à fait le même comportement au niveau du rapport d'erreurs...

    Des quelques essais que j'ai pu faire, lorsque j'utilise CodeDomProvider.CreateProvider("csharp"), j'ai un rapport d'erreur plus complet plus rapidement alors qu'en utilisant new CSharpCodeProvider() du Nuget Package.

    Exemple :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        public static class MaClasseStaticPourExtension
        {
            public static MaClasseDeRetour MonExtensionSpecifique(this MaClasseDEntree This)
            {
                return This.MonExtensionDeBase<MonParametreT>((data) => { return This.UneAutreExtensionDansUnAutreFichier(); });
            }
        }

    Le premier me retourne une première erreur disant qu'il ne connait pas le lien avec MaClasseDEntree que je m'empresse de lui donner pour recompiler mais déjà ce n'est pas tout à fait pareil :
    • CodeDomProvider.CreateProvider("csharp")
      CS1061 : ''MonProjet.MonEspaceDeNom.MaClasseDEntree' ne contient pas une définition pour 'MonExtensionDeBase' et aucune méthode d'extension 'MonExtensionDeBase' acceptant un premier argument de type 'MonProjet.MonEspaceDeNom.MaClasseDEntree' n'a été trouvée (une directive using ou une référence d'assembly est-elle manquante*?)'
    • new CSharpCodeProvider() du Nuget Package
      CS1061 : ''MaClasseDEntree' does not contain a definition for 'MonExtensionDeBase' and no accessible extension method 'MonExtensionDeBase' accepting a first argument of type 'MaClasseDEntree' could be found (are you missing a using directive or an assembly reference?)


    Déjà là on n'est pas pareil car le nom donné est le nom complet pour l'un et juste le nom pour l'autre.

    Puis En mettant le lien vers cette DLL
    • CodeDomProvider.CreateProvider("csharp")
      CS0006 : 'Le fichier de métadonnées 'Compiled\UneAutreExtensionDansUnAutreFichier.dll' est introuvable'
      et
      CS0006 : 'Le fichier de métadonnées 'Compiled\MonExtensionDeBase.dll' est introuvable'
    • new CSharpCodeProvider() du Nuget Package
      CS0006 : 'Metadata file 'Compiled\MonExtensionDeBase.dll' could not be found'


    Et là, je n'ai qu'une seule erreur au lieu des 2 normalement attendues me permettant ainsi de terminer mes liens pour ma compilation...

    Je pense que j'arriverai à adapter la manière de fonctionner mais cela me laisse quand même quelques inquiétudes...

    En tout cas, merci pour ce bout de code complet que j'ai pu prétester avant de mettre en place dans mon code et arriver à ce constat d'écart.

+ 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