Compilation de code à la volée
Bonjour,
J'ai 2 questions pour le prix d'une.
:help:
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:
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 :ccool:
Maintenant, je souhaite l'exécuter avec le code suivant :
Code:
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 :
Citation:
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 ? :aie:
:zen:
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 :king:
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... :pleure:
Seconde question :
Dans le code, j'ai
Code:
int a = 1; Console.WriteLine(a.ToString("00"))
Que j'ai transformé en
Code:
int a = 1; Console.WriteLine($"{a:00}"))
Et là, à la compilation, j'ai cette erreur :
Citation:
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 ? :koi:
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. :hola:
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. 8-)
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). :langue2:
Reste la seconde question à propos du sucre syntaxique, des idées à propos de ce $ ? :cfou:
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:
var a = MonObjet?.MaPropriete;
, contraction de
Code:
var a = null; if (MonObjet != null) a = MonObjet.MaPropriete;
J'ai 3 erreurs d'un coup :
Citation:
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 ?