How to reproduce:
var script = CSharpScript.Create("a + b");
dynamic expando = new ExpandoObject();
var dictionary = (IDictionary<String, Object>) expando;
dictionary.Add("a", 3);
dictionary.Add("b", 4);
script.Run(expando);
Gives error message:
The name 'b' does not exist in the current context
Is there another, recommended way of giving a dynamically built object as the globals parameter to the script?
The cause of this not being supported can be found in https://github.com/dotnet/roslyn/blob/03e30451ce7eb518e364b5806c524623424103e4/src/Scripting/Core/ScriptVariables.cs#L98 where it finds the fields and properties of the given instance and converts it into a map of script variables.
If this could check if the object is an IDictionary
Or am I completely off-base? I don't know the codebase well-enough to actually be confident.
@Stmated Thanks for letting us know that this feature is important for you. Currently the ability to use a dynamic object as a host object is not supported. We have it on backlog.
BTW, the spot you identified is not the only place that would need to implement support for dynamic variables.
Yes, launching csi.exe /r:System.Dynamic
(as of revision 232206a6fdabd437ccd64d185e3938db47030b16) and typing:
C#
using System.Dynamic;
var i = 1;
dynamic d = i;
d.ToString();
fails with error CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'
for instance. Every access to a dynamic variable members seem to fail with that error from what I can tell.
Great to see the REPL in csi.exe though :tada:
The command line processing is not all working yet. Try:
> #r "System.Dynamic"
> #r "Microsoft.CSharp"
> dynamic d = 1;
> d.ToString()
"1"
(btw, these assemblies should be available by default).
Great, thanks! Not the first time I forgot Microsoft.CSharp.
@Stmated did you find a workaround for that?
Or @tmat is there any status update on the backlog item?
We would really need something like this, to be able to provide globals dynamically... We also tried to create a type dynamically as suggested here: http://stackoverflow.com/questions/29413942/c-sharp-anonymous-object-with-properties-from-dictionary/29428640#29428640, but this was not working (probably caused by #2246).
Thanks for your feedback,
Markus
No update, it's still on backlog.
An alternative workaround would be to add an indirection:
C#
var script = CSharpScript.Create("dyn.a + dyn.b");
...
script.Run(new { dyn = expando })
@tmat: Thank you very much, that is a nice workaround! I will rewrite my code until this is implemented!
@tmat Thanks for the workaround! This topic has provided a lot of help regarding importing dynamic global to the Roslyn scripting context.
The entire scripting API has been a pleasure to work with except for this little missing feature. I assume there is not update on this backlog item. Is there a way to vote for this feature?
In my scenario, I am providing an in-game REPL console where users can dynamically add variables to be modified at runtime. While the workaround works, it is causing a lot of headache with the current console's autocompletion system and generally doesn't "feel" nice.
@tmat what is status of this one? Would really need the possibility for dynamic global without above workaround!
Also looking for a status update? I've implemented the workaround but would prefer not having to access 'globals' from another member.
Any update on this issue, or is it still on the backlog?
edit: solved our needs with the example below
// for sending in parameters to the script
public class Globals
{
public dynamic data;
}
// Script that will use dynamic
var scriptContent = "data.X + data.Y";
// data to be sent into the script
dynamic expando = new ExpandoObject();
expando.X = 34;
expando.Y = 45;
// setup references needed
var refs = new List<MetadataReference>{
MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).GetTypeInfo().Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Runtime.CompilerServices.DynamicAttribute).GetTypeInfo().Assembly.Location)};
var script = CSharpScript.Create(scriptContent, options: ScriptOptions.Default.AddReferences(refs), globalsType: typeof(Globals));
script.Compile();
// create new global that will contain the data we want to send into the script
var g = new Globals() { data = expando };
//Execute and display result
var r = script.RunAsync(g).Result;
Console.WriteLine(r.ReturnValue);
When running the above example I get
Microsoft.CodeAnalysis.Scripting.CompilationErrorException: "(1,1): error CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.Binder.BinaryOperation'"
which is in Microsoft.CSharp.dll
Did this happen to anyone else?
@schprl We've just had an issue regarding dynamic objects and Microsoft.CSharp.dll. We had to remove the Microsoft.CSharp.dll assembly reference to get dynamics working. Might be related.
Just tried to use ExpandoObject today and it appears this is still not supported. However as I still need to accept on-demand globals just before the script is executed, I am currently trying the following workaround:
test
, the generated script would be int test = default(int);
Why Roslyn is not supporting ExpandoObject or Anonymous. Is there any reason?
Most helpful comment
Also looking for a status update? I've implemented the workaround but would prefer not having to access 'globals' from another member.