Could Roslyn compile await keyword? - c#

While working with latest version of roslyn-ctp I have found that it does not support dynamic keyword while compiling and script execution, i.e. you will get an compiling error error CS8000: This language feature ('dynamic') is not yet implemented in Roslyn. Here is a short code snippet:
var engine = new ScriptEngine();
var script = #"dynamic someVariable = 0;";
// you an error CS8000: This language feature ('dynamic') is not yet implemented in Roslyn
engine.CreateSession().Execute(script);
While working with await keyword…
In contrast, while working with await keyword at compilation or script, I usually got some random compilation error like one of followings:
error CS1001: Identifier expected
error CS1003: Syntax error, ',' expected
error CS0246: The type or namespace name 'await' could not be found (are you missing a using directive or an assembly reference?)
Sample of scripting
var engine = new ScriptEngine();
new[]
{
"System", "System.Threading", "System.Threading.Tasks",
} .ToList().ForEach(#namespace => engine.ImportNamespace(#namespace));
var script = #"await Task.Run(() => System.Console.WriteLine(""Universal [async] answer is '42'""));";
engine.CreateSession().Execute(script);
Sample of compilation
// compilation sample
const string codeSnippet = #"namespace DemoNamespace
{
using System;
using System.Threading;
using System.Threading.Tasks;
public class Printer
{
public async void Answer()
{
var answer = 42;
var task = Task.Run(() => System.Console.WriteLine(string.Format(""Universal [async] answer is '{0}'"", answer)));
await task; // not working
task.Wait(); // working as expected
}
}
}";
var syntaxTree = SyntaxTree.ParseText(codeSnippet,
options: new ParseOptions(languageVersion: LanguageVersion.CSharp5));
var references = new []
{
MetadataReference.CreateAssemblyReference(typeof(Console).Assembly.FullName),
MetadataReference.CreateAssemblyReference(typeof(System.Threading.Tasks.Task).Assembly.FullName),
};
var compilation = Compilation.Create(
outputName: "Demo",
options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary),
syntaxTrees: new[] { syntaxTree },
references: references);
if(compilation.GetDiagnostics().Any())
{
compilation.GetDiagnostics().Select(diagnostic => diagnostic).Dump();
throw new Exception("Compilation failed");
}
Assembly compiledAssembly;
using (var stream = new MemoryStream())
{
EmitResult compileResult = compilation.Emit(stream);
compiledAssembly = Assembly.Load(stream.GetBuffer());
}
dynamic instance = Activator.CreateInstance(compiledAssembly.GetTypes().First());
instance.Answer();
Q: Am I missing something or it is not implemented yet?
I have tried different configuration with LanguageVersion.CSharp5 and without. Both Google and Stackoverflow searches are full of marketing hype for both roslyn and async keywords and almost useless. Microsoft "Roslyn" CTP forum also has no answer for this.
ps: as far as I know async keyword has introduced for readability both by humans and compilers while await does all magic

await support is not implemented in the current Roslyn CTP (although it is now implemented in internal builds).
The reason for the difference in error reporting is that we first built the Roslyn parser so that it could handle the entire C# 4 language, and then filled in semantics for features one at a time. Since await is a C# 5 feature, it is not even recognized by the parser, and there is no place to recognize its use and provide a good error.

Actually, the Roslyn forum does have the answer. If you look at the post Known Limitations and Unimplemented Language Features, you'll notice that it contains “Async” among the not yet implemented features in C#.
That list is about the June CTP, but since the list of changes between the June CTP and the December CTP doesn't list async, it means it's simply not implemented yet.
I think the reason for the difference in error message is that Roslyn does understand dynamic (but doesn't implement it yet). On the other hand, it doesn't understand async-await, so it gives you generic compilation errors.

Related

In C#, I am getting an error when requesting permission for speech recognition Xamarin Android

So I am using the Plugin.SpeechRecognition Nuget Package and following the exact code on line and its not working.
I have tried adding the "Plugin.Permissions" Nuget Package and that hasn't helped and i have tried googling the problem but there isn't anyone getting this issue and it seems to work fine for everyone. I have also tried removing the "await" keyword and it just says
Operator '==' cannot be applied to operands of type 'IObservable' and 'bool'
Here is my code:
private async void GetSpeechPermission()
{
var granted = await CrossSpeechRecognition.Current.RequestPermission();
if (granted == true)
{
// go!
}
}
so what should happen is there is no error what so ever and the code should run fine but the line of code
await CrossSpeechRecognition.Current.RequestPermission();
has a red underline saying
IObservable' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'IObservable' could be found (are you missing a using directive or an assembly reference?)
when I am using the EXACT code provided by the creator of the plugin from here https://github.com/aritchie/speechrecognition
Any help is MUCH appreciated!!
The Solution to this was to add
using System.Reactive.Linq
in the using section of the code and instead of using a bool value as the code example for the plugin suggests, instead, in the if statement, convert the "granted" variable to a string and then check for "Available", Code:
private async void GetSpeechPermission()
{
var granted = await CrossSpeechRecognition.Current.RequestPermission();
if (granted.ToString() == "Available")
{
//GO
}
}
Hope this helps some one! :D

Json with C# and Mono

I'm trying to read a json string into memory and get this undocumented error msg
$ mcs -r:FortnoxAPILibrary.dll -r:npgsql.dll -r:System.Data.dll -r:Newtonsoft.Json.dll Vouchers.cs
Vouchers.cs(44,18): error CS0103: The name `JArray' does not exist in the current context
Compilation failed: 1 error(s), 0 warnings
My code is
var json = System.IO.File.ReadAllText("test.json");
var objects = JArray.Parse(json); // parse as array
foreach(JObject root in objects)
{
foreach(KeyValuePair<String, JToken> app in root)
{
var appName = app.Key;
var description = (String)app.Value["Description"];
var value = (String)app.Value["Value"];
Console.WriteLine(appName);
Console.WriteLine(description);
Console.WriteLine(value);
Console.WriteLine("\n");
}
}
Where is it documented how this should work?
You are more than likely missing a using statement.
using Newtonsoft.Json.Linq;
Every piece of C# code you write, except for core types, requires a using statement pointing to any dependencies.
C# libraries often don't document the using statement requirements for a block of code. Maybe an oversight, but most users are using an IDE, which warns of the missing statement and offers options to automatically insert them.
It is not documented that I must include this line.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

CsScript with Mono: How to make mono not treat warnings as errors

I use CSScriptLibrary.dll to execute C# code in my application which runs on both Windows and Linux. Problem is, right now, I need to use #pragma disable warning to disable all kinds of warnings that may arise in order to get the scripts to compile on Mono which is a very ugly hack.
// the following simple script will not execute on Mono due to a warning that a is not used.
var code = "public class Script { public object Run() { var a=1; return 2+3; }}"
// here is how the script is executed using CsScriptLibrary
try
{
var asm = new AsmHelper(CSScript.LoadCode(code, "cs", null, true));
// if we reach that point, the script compiled
var obj = asm.CreateAndAlignToInterface<IScript>("*");
// now run it:
var result=obj.Run();
}
catch (CompilerException e)
{
// on .net compiler exceptions are only raised when there are errors
// on mono I get an exception here, even for warnings like unused variable
}
I already tried to set the default compiler parameters of CSScript to instruct the mono compiler to disregard warnings. Here is what I tried (based on documentation of compiler switches of Mono compiler:
CSScript.GlobalSettings.DefaultArguments = "-warn:0 -warnaserror-";
But I had no success and I am not even sure if this is the right way to go. Anyway, for the sake of completeness I note here that CSScript.GlobalSettings.DefaultArguments defaults to /c /sconfig /co:/warn:0 in CSScript.
Does anyone know how to get CSScript.LoadCode to disregard warnings on Mono or at least not treat them as errors?
Here are two solutions (found with help of Oleg Shilo). You can either include the desired compiler option directly in the script:
//css_co -warn:0
using System;
...
or you can substitute CSScript.LoadCode with LoadWithConfig, which allows passing compiler options directly. Something like this:
static public Assembly LoadCode(string scriptText, bool debugBuild, params string[] refAssemblies)
{
string tempFile = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() +".cs";
try
{
using (StreamWriter sw = new StreamWriter(tempFile))
sw.Write(scriptText);
return LoadWithConfig(scriptFile, null, debugBuild, CSScript.GlobalSettings, "-warn:0", refAssemblies);
}
finally
{
if (!debugBuild)
{
//delete temp file
}
}
}
It should be noted, that the second solution will bypass the built in assembly caching performed in LoadCode. It is easy enough to cache the compiled script object though.

Using Roslyn Emit method with a ModuleBuilder instead of a MemoryStream

I was having trouble with performance when using Roslyn to compile to a dynamic assembly. Compilation was taking ~3 seconds, compared to ~300 milliseconds to compile the same code when using the CodeDom compiler. Here's a pared-down version of the code I'm using to do the compilation:
var compilation = CSharpCompilation.Create(
"UserPayRules.dll",
syntaxTrees,
assembliesToAdd);
using (var stream = new MemoryStream())
{
stopWatch.Start();
var result = compilation.Emit(stream);
stopWatch.Stop();
Debug.WriteLine("Compilation: {0}", stopWatch.ElapsedMilliseconds);
if (!result.Success)
{
throw new InvalidOperationException();
}
var assembly = Assembly.Load(stream.GetBuffer());
}
This answer suggests passing a ModuleBuilder object into the Emit method instead of a MemoryStream in order to speed things up. I tried to follow that pattern, like so:
var compilation = CSharpCompilation.Create(
"UserPayRules.dll",
syntaxTrees,
assembliesToAdd);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("ThisAssembly"),
AssemblyBuilderAccess.RunAndCollect);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("ThisModule");
var result = compilation.Emit(moduleBuilder);
Debug.WriteLine("Compilation: {0}", stopWatch.ElapsedMilliseconds);
if (!result.Success)
{
throw new InvalidOperationException();
}
var assembly = Assembly.Load(stream.GetBuffer());
But my version of Roslyn apparently doesn't have an overload of the Emit method that takes a ModuleBuilder. That version is:
Id: Microsoft.CodeAnalysis
Version: 0.6.4033103-beta (Prerelease)
Project Information: http://msdn.microsoft.com/en-US/roslyn
Obviously, this is a prerelease, so it's not strange that the api might have changed. However,
My Question(s)
Does anyone know why the Emit method no longer seems to have an overload that takes a ModuleBuilder?
Is there another way to make this compilation faster while still using Roslyn (Roslyn offers a couple advantages over the CodeDom and Mono compilers that I'd prefer not to give up)?
Roslyn currently doesn't expose ability to emit dynamic assemblies. We removed it because it was problematic.
You can still emit to a MemoryStream using Compilation.Emit APIs and then use Assembly.Load(byte[]) to load the resulting binary.
Note that this assembly won't be freed until the containing AppDomain is unloaded.

Razor ViewEngine Temporary compilation .cs files

When calling the Parse method in the Razor ViewEngine, compilation errors are thrown as TemplateComplilationException which contains a list of errors. Those errors refer to temporary filenames, but the files are deleted before you can access them.
static void Main(string[] args)
{
var service = TemplateServiceFactory.CreateTemplateService(Language.CSharp, true);
string result = "";
try
{
result = service.Parse("Hello #DateTime.NowXX ");
}
catch (TemplateCompilationException ex)
{
foreach (var error in ex.Errors)
if (!string.IsNullOrEmpty(error.FileName))
Console.WriteLine( File.ReadAllText( error.FileName ));
} // ^^^^ File does not exist!
Console.WriteLine( result );
Console.ReadKey();
}
(a little background)
I'm using the Razor engine "stand-alone" without MVC. When I call the Parse I want to get as much detailed information as possible to display to the user.
The current v2.1 release doesn't provide the ability to spit out the source code. There is a debugging feature in the new v3 codebase that allows the source code to be pushed out. It doesn't do this by default, because I'm trying to make the code as performant as possible (and generating the code twice (once as CodeDom, once as a string) isn't ideal). You'll need to enable the Debug flag on your configuration:
var config = new TemplateServiceConfiguration { Debug = true };
var service = new TemplateService(config);
This will enable the source code to be read when an exception is thrown.
Point of interest, through testing the Roslyn compiler infrastructure with the v3 codebase, it accepts a string source instead of CodeDom, so I'll likely make a future change to use that instead of CodeDom directly - this in turn means we have direct access to the source code without having to worry about enabling any Debug flag which will likely be deprecated.
v3 (currently v3.0.7beta) is available on Nuget (Install-Package RazorEngine). I was aiming to RTW last weekend but never got round to it.
RazorEngine's TemplateCompilationException is a class that wraps a CompilerErrorCollection that contain CompilerError objects, so the most details you could possibly get from the TemplateCompilationException CompilerError objects are their respective properties, which appears to be enough to debug with. Consider and try this example
try
{
Razor.Parse("My erroneous #DateTime.Now.foo()");
}
catch(TemplateCompilationException ex)
{
foreach(var error in ex.Errors)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("Compile Error Num: \t" + error.ErrorNumber);
sb.AppendLine("Error Text:\n\t" + error.ErrorText);
Console.WriteLine(sb.ToString());
}
Console.WriteLine("Erroneous Template:\n\t" + ex.Template);
}
When I run my example this is what I get, which tells you the error(s) that was encountered and you can dump the template data to reference for your users.
Compile Error Num: CS1061
Error Text:
'System.DateTime' does not contain a definition for 'foo' and no
extension method 'foo' accepting a first argument of type
'System.DateTime' could be found (are you missing a using directive
or an assembly reference?)
Erroneous Template:
My erroneous #DateTime.Now.foo()

Categories

Resources