Unity cannot build GRPC Project for UWP with IL2CPP Backend - visual-studio

Here, or here for a complete version, you can find a sample GRPC "Hello World" project for Unity. Only the first version, that is built for Unity and wrapped in a DLL is working perfectly fine in Unity IDE and on Standalone build. The Raw Grpc.Core files are referencing everything correctly in IDE but they have Marshaling problem.
Unfortunately, it cannot get build for UWP with IL2CPP backend. Unity builds the project and creates a .sln project. But Visual Studio always gives LNK2001 for GRPC properties on the final compilation.
Here are first error codes:
LNK2001 unresolved external _grpccsharp_init#0
LNK2001 unresolved external _grpccsharp_shutdonw#0
LNK2001 unresolved external _grpccsharp_version_string#0
...
Ok, thanks to #Sunius, I digged into it a little bit more. There are some points, I am going to add to the question:
There are two methods regarding referencing extern methods in GRPC C# package. They are named static and shared libs.
internal class DllImportsFromStaticLib
{
private const string ImportName = "__Internal";
[DllImport(ImportName)]
public static extern void grpcsharp_init();
[DllImport(ImportName)]
public static extern void grpcsharp_shutdown();
...
}
and
internal class DllImportsFromSharedLib
{
private const string ImportName = "grpc_csharp_ext";
[DllImport(ImportName)]
public static extern void grpcsharp_init();
[DllImport(ImportName)]
public static extern void grpcsharp_shutdown();
...
}
I tried to test it with the shared one, I got another linking error file which is a little bit different.
LNK2001 unresolved external _dlopen#8
LNK2001 unresolved external _dlsym#8
...
In two separate methods, extern methods are getting connected to the internal interface:
public NativeMethods(DllImportsFromStaticLib unusedInstance)
{
this.grpccsharp_init = DllImportsFromStaticLib.grpccsharp_init;
this.grpccsharp_shutdown = DllImportsFromStaticLib.grpccsharp_shutdonw;
...
}
and
public NativeMethods(DllImportsFromSharedLib unusedInstance)
{
this.grpccsharp_init = DllImportsFromSharedLib.grpccsharp_init;
this.grpccsharp_shutdown = DllImportsFromSharedLib.grpccsharp_shutdonw;
...
}
And which method will get called is defined here:
private static NativMethods LoadNativeMethodsUnity()
{
switch(PlatformApis.GetUnityRuntimePlatform())
{
case "IPhonePlayer":
return new NativeMethods(new NativeMethods.DllImportsFromStaticLib());
default:
return new NativeMethods(new NativeMethods.DllImportsFromSharedLib());
}
}
Some updates:
Thanks to #jsmouret, there is Stub.c file in his Grpc Github with fake methods, so Linker does not complain about Grpc_init methods anymore.
Next Error: dlopen, dlsym, dlerror:
First, I tried to use the same, Stub technique, but it did not help in this case, or maybe I did it wrong.
Thanks to #Sunius, I commented out all of "__Internal" dll import codes. So I am not getting any dlopen, dlsym, and dlerror errors.
Next Error: It happens from inside application, not the visual studio debugger. It tells me: "exception: to marshal a managed method, please add an attribute named 'MonoPInvokeCallback' to the method definition."
exception: error loading the embedded resource "Grpc.Core.roots.pem"
and
exception: To marshal a managed method, please add an attribute named 'MonoPInvokeCallback' to the method definition.
After I googled it, I know my options, but the question it, for which method should I do that?!

Thanks to my colleague Alice, #Sunius and #jsmouret, at the end, grpc works on UWP on Unity Platform through this steps:
Download Grpc.Core folder from Google Grpc Github.
Download Grpc Unity plugin from their official site.
Copy the runtime folder to your Grpc.Core folder. Please remove Grpc.Core.dll that you get from Grpc Unity Plugin, since we are using their source code.
Grpc should be in a folder called, Plugins in Unity, otherwise it will not be recognized.
Include this file in your runtime folder.
Include the Stub also from the Unity Plugin Inspector for WSA.
Find runtime .dll for Windows and include them in WSA from Unity Plugin Inspector.
By now, you should be getting _dlopen error.
Search through your Unity Solution with an IDE for "__Internal". There are not so many places, but comment them out. Also some methods that are depended on "__Internal"s, like dlopen and dlsym.
By now, you are not getting anymore build error but you need to make Grpc work.
Search for something like "DefaultSslRootsOverride" and comment out like below:
internal static class DefaultSslRootsOverride
{
const string RootsPemResourceName = "Grpc.Core.roots.pem";
static object staticLock = new object();
/// <summary>
/// Overrides C core's default roots with roots.pem loaded as embedded resource.
/// </summary>
public static void Override(NativeMethods native)
{
lock (staticLock)
{
//var stream = typeof(DefaultSslRootsOverride).GetTypeInfo().Assembly.GetManifestResourceStream(RootsPemResourceName);
//if (stream == null)
//{
// throw new IOException(string.Format("Error loading the embedded resource \"{0}\"", RootsPemResourceName));
//}
//using (var streamReader = new StreamReader(stream))
//{
// var pemRootCerts = streamReader.ReadToEnd();
// native.grpcsharp_override_default_ssl_roots(pemRootCerts);
//}
}
}
}
Search for something like "static void HandWrite" and add an attribute like something in below:
[MonoPInvokeCallback(typeof(GprLogDelegate))]
private static void HandleWrite(IntPtr fileStringPtr, int line, ulong threadId, IntPtr severityStringPtr, IntPtr msgPtr)
{
try
{
var logger = GrpcEnvironment.Logger;
string severityString = Marshal.PtrToStringAnsi(severityStringPtr);
string message = string.Format("{0} {1}:{2}: {3}",
threadId,
Marshal.PtrToStringAnsi(fileStringPtr),
line,
Marshal.PtrToStringAnsi(msgPtr));
switch (severityString)
{
case "D":
logger.Debug(message);
break;
case "I":
logger.Info(message);
break;
case "E":
logger.Error(message);
break;
default:
// severity not recognized, default to error.
logger.Error(message);
break;
}
}
catch (Exception e)
{
Console.WriteLine("Caught exception in native callback " + e);
}
}
I guess, you are done. In case, it did not work for your UWP, let me know, maybe I can help. :)

It looks like your plugin uses "__Internal" P/Invoke to call those native functions:
https://github.com/grpc/grpc/blob/befc7220cadb963755de86763a04ab6f9dc14200/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs#L542
However, the linker cannot locate those functions and thus fails. You should change that code to either specify the DLL file name where the functions are implemented, or drop the source files with definitions for those functions into your Unity project. Or, if that code path isn't actually invoked (since you said it works on the standalone player), #ifdef it out from UWP build.
You can find more information about "__Internal" P/Invoke here:
https://docs.unity3d.com/Manual/windowsstore-plugins-il2cpp.html

Related

Recompile assemblies to separate appdomains in NET 5

I have a NET 5.0 console application, from which I am trying to compile and execute external code BUT also be able to update the code, unload the previously created appdomain and re-compile everything.
This is my entire static class that handles code compilation and assembly loading
using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;
using Microsoft.CodeAnalysis.Emit;
using System.Runtime.Loader;
namespace Scripting
{
public static class ScriptCompiler
{
public static Dictionary<string, AppDomain> _appDomainDict = new();
public static object CompileScript(string scriptpath)
{
var tree = SyntaxFactory.ParseSyntaxTree(File.ReadAllText(scriptpath));
//Adding basic references
List<PortableExecutableReference> refs = new List<PortableExecutableReference>();
var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
refs.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "mscorlib.dll")));
refs.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.dll")));
refs.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Private.CoreLib.dll")));
refs.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Core.dll")));
refs.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Runtime.dll")));
// A single, immutable invocation to the compiler
// to produce a library
string hash_name = scriptpath.GetHashCode();
if (_appDomainDict.ContainsKey(hash_name))
{
AppDomain.Unload(_appDomainDict[hash_name]);
_appDomainDict.Remove(hash_name);
}
AppDomain new_domain = AppDomain.CreateDomain(hash_name);
_appDomainDict[hash_name] = new_domain;
var compilation = CSharpCompilation.Create(hash_name)
.WithOptions(
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: OptimizationLevel.Release,
allowUnsafe:true))
.AddReferences(refs.ToArray())
.AddSyntaxTrees(tree);
MemoryStream ms = new MemoryStream();
EmitResult compilationResult = compilation.Emit(ms);
ms.Seek(0, SeekOrigin.Begin);
if (compilationResult.Success)
{
// Load the assembly
Assembly asm = new_domain.Load(ms.ToArray());
object main_ob = asm.CreateInstance("SomeClass");
ms.Close();
return main_ob;
}
else
{
foreach (Diagnostic codeIssue in compilationResult.Diagnostics)
{
string issue = $"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()}," +
$" Location: { codeIssue.Location.GetLineSpan()}," +
$" Severity: { codeIssue.Severity}";
Callbacks.Logger.Log(typeof(NbScriptCompiler), issue, LogVerbosityLevel.WARNING);
}
return null;
}
}
}
}
Its all good when I am trying load the assembly in the current domain and execute from the instantiated object. The problem with this case is that since I wanna do frequent updates to the code, even if I make sure that the assembly names are different. I'll end up loading a ton of unused assemblies to the current domain.
This is why I've been trying to create a new domain and load the assembly there. But for some reason I get a platform not supported exception. Is this not possible to do in NET 5? Are there any workarounds or am I doing something wrong here.
Ok, it turns out that AppDomain support for NET Core + is very limited and in particular there seems to be only one appdomain
On .NET Core, the AppDomain implementation is limited by design and
does not provide isolation, unloading, or security boundaries. For
.NET Core, there is exactly one AppDomain. Isolation and unloading are
provided through AssemblyLoadContext. Security boundaries should be
provided by process boundaries and appropriate remoting techniques.
Source: https://learn.microsoft.com/en-us/dotnet/api/system.appdomain?view=net-6.0
And indeed, when trying to use AssemblyLoadContext and create object instances through these contexts everything worked like a charm!
One last note is that if the created context is not marked as collectible, its not possible to unload it. But this can be very easily set during AssemblyLoadContext construction.

Resolve actual Reference path using Microsoft.Build.Evaluation

I'm doing some introspection and analysis of csproj files using the Microsoft.Build.Evaluation tools in a small C# console app. I want to locate the actual location of Reference items, using the same heuristics as MSBuild itself ie the locations described here. I'm heading towards auto conversion of build artifacts into packages, similar to what's outlined on the JetBrains blog here
The only examples I can find expect the HintPath to be correct, for example this project, and I know there are some HintPaths that are not currently correct, I don't want to trust them. This project very close what I'm trying to do, with the added complication that I want to use real resolution behaviour to find dependencies.
I have an instance of a Microsoft.Build.Evaluation.Project object for my csproj, and I can't see any methods available on it that could exersize the resolution for me. I think what I'm hoping for is a magic Resolve() method for a Reference or a ProjectItem, a bit like this method.
I can probably find an alternative by constraining my own search to a set of limited output paths used by this build system, but I'd like to hook into MSBuild if I can.
The reference resolution is one of the trickiest parts of MSBuild. The logic of how assemblies are located is implemented inside the a standard set of tasks:
ResolveAssemblyReference, ResolveNativeReference, etc. The logic is how this works is very complicated, you can see that just by looking at number of possible parameters to those tasks.
However you don't need to know the exact logic to find the location of referenced files. There are standard targets called "ResolveAssemblyReferences", "ResolveProjectReferences" and some others more specialized for native references, COM references. Those targets are executed as part of the normal build. If you just execute those targets separately, you can find out the return values, which is exactly what you need. The same mechanism is used by IDE to get location of refereces, for Intellisense, introspection, etc.
Here is how you can do it in code:
using Microsoft.Build.BuildEngine;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;
class Program
{
static int Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: GetReferences.exe <projectFileName>");
return -1;
}
string projectFileName = args[0];
ConsoleLogger logger = new ConsoleLogger(LoggerVerbosity.Normal);
BuildManager manager = BuildManager.DefaultBuildManager;
ProjectInstance projectInstance = new ProjectInstance(projectFileName);
var result = manager.Build(
new BuildParameters()
{
DetailedSummary = true,
Loggers = new List<ILogger>() { logger }
},
new BuildRequestData(projectInstance, new string[]
{
"ResolveProjectReferences",
"ResolveAssemblyReferences"
}));
PrintResultItems(result, "ResolveProjectReferences");
PrintResultItems(result, "ResolveAssemblyReferences");
return 0;
}
private static void PrintResultItems(BuildResult result, string targetName)
{
var buildResult = result.ResultsByTarget[targetName];
var buildResultItems = buildResult.Items;
if (buildResultItems.Length == 0)
{
Console.WriteLine("No refereces detected in target {0}.", targetName);
return;
}
foreach (var item in buildResultItems)
{
Console.WriteLine("{0} reference: {1}", targetName, item.ItemSpec);
}
}
}
Notice, the engine is called to invoke specific targets in the project. Your project usually does not build, but some targets might be invoked by pre-requisite targets.
Just compile it and will print a sub-set of all dependencies. There might be more dependencies if you use COM references or native dependencies for your project. It should be easy to modify the sample to get those as well.

Java debugger can't call some default method implementations

I'm coding in IntelliJ IDEA. When debugging my application, I can't use some default method implementations in Watches.
Here is a condensed example:
public class Friendship {
interface Friend {
default void sayHiTo(Friend friend) {
System.out.println("Hi, " + friend.hashCode());
}
default int amountOfHands() {
return 2;
}
}
public static class BasicFriend implements Friend {
int numberOfFaces() {
return 1;
}
}
public static void main(String[] args) {
System.out.println("Put a breakpoint here");
}
}
In main() method I put a breakpoint and set up three watches:
// Default interface method with dependency
new BasicFriend().sayHiTo(new BasicFriend())
// Default interface method without dependency
new BasicFriend().amountOfHands()
// Class method
new BasicFriend().numberOfFaces()
The first watch throws NoSuchMethodException complaining that method Friendship$BasicFriend.sayHiTo() doesn't exist.
The second watch runs successfully, but strangely it reports a boxed object
{java.lang.Integer#537} "2" instead of just a primitive 2.
The third watch reports a primitive 1, just as expected.
Why is the first watch not working? Is this a bug? Is this actually IDE related? Is it because of some conceptual flaw of default methods? Should it be working as I want it to in the first place? Is the strange result of the second watch somehow related to the issue in the first watch?
Prior to JDK 8u40, default and static interface methods were not supported by JDI (Java Debugger Interface), JDWP (Java Debugger Wire Protocol) and JDB (the standard Java debugger). This is bug JDK-8042123, which is recorded as fixed in 8u40 and a corresponding blurb appears in the 8u40 release notes.
Update to 8u40 or later to fix this issue, at least on the JDK side.
From the bug description, it looks like debugger-side changes are also required, to avoid casting com.sun.jdi.InterfaceType objects to com.sun.jdi.ClassType, but instead call InterfaceType.invokeMethod() directly.
In the specific case of IntelliJ, Suseika confirmed in a comment that 14.1.2 has mostly fixed the issue (except the unexpected boxing), though Mike Kobit still experiences this problem on that version with a ClassCastException suggestive of the incorrect cast above.

Generate Bare Definitions for a Project or Namespace (Visual Studio)

In developing an SDK for use within our product, we want to provide users (developers) a Visual Studio plugin, mainly to provide them Intellisense during their development and ensure their code compiles for them. To do this, we strip the contents of all of our SDK APIs and put them all in a separate project.
For example:
public IEnumerable<string> AvailableConnections(bool querySystem) {
var connections = ConnectionList();
if(querySystem)
connections = connections.Concat(SystemConnections());
... // Filter connections somehow
return connections;
}
public void WriteToStream(Stream strFrom, Stream strTo) {
byte[] buffer = new byte[32 * 1024]; // 32 KiB
int len;
while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, len);
}
}
Becomes:
public IEnumerable<string> AvailableConnections(bool querySystem) { return null; }
public void WriteToStream(Stream strFrom, Stream strTo) { }
My question: Does a tool exist to automate this, whether for a particular project or particular namespace? Ideally, it would intake a project or namespace and output all of the public classes/functions replacing their definitions with a simple return of the return type's default value. Visual Studio seems to do almost this when you view a class from which you don't have the source (e.g., you'll see IEnumerable<T> [from metadata]).
It sounds like you want to provide interfaces to your API.
You can build this into your project and essentially you will always have an assembly that shows all the public members without containing your implementation code.
Create a project that contains only the API, and reference that from your main project so that your concrete code (your implementation) implements the interfaces.
The API assembly would contain mostly interfaces and perhaps some abstract classes an helper, which you could share with developers.
Taking your example, you would have an interface like
public interface IMySdkThing
{
IEnumerable<string> AvailableConnections(bool querySystem);
void WriteToStream(Stream strFrom, Stream strTo);
}
Your implementation would be declared like:
public class MySdkThing : IMySdkThing
{
// all the code you showed, just as it is
}
All that said, it isn't clear how this will be useful to the developer. He or she will need a dll with some actual, executable code in it to use your library. Intellisense and compile-time checking come for free; you don't have to do anything special.

C#5 AsyncCtp BadImageFormatException

Please help me with this one, I've been writing a console applicaiton using the AsyncCtpLibrary and the C#5 ctp compiler. First time I got to actually running a code which awaits, I got this:
System.BadImageFormatException was unhandled
Message=An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
Source=AsyncCtpLibrary
StackTrace:
Server stack trace:
at [...].<Execute>d__1c.MoveNext()
at [...].Execute()
at [...].<Move>d__1d.MoveNext() in[..]:line 266
Exception rethrown at [0]:
at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.<SetException>b__1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
InnerException:
Am I missing a dll to be referenced?
important new stuff
My failing method looks like this:
public async override Task<bool> Execute()
{
//do stuff
await stuff;
//do other stuff
await base.Execute()
//do other stuff
return true;
}
I've followed Jon Skeet's advice trying to recreate the mistake little by little, and now I can tell that the await base.Execute() line is the killer! If I comment that line out, everything runs, if I leave it in, calling my method fails IMMEDIATELY (not when reaching the base.Execute()). So I assume the ctp compiler does something freaky. Why? What should I never do? How big is the bug?
old stuff:
EDIT:
As for 32bit/64bit issue, my system is 32bit (inside a virtual machine, mind you), and as far as I know AsyncCtpLibrary.dll doesn't contain unmanaged code. All my projects (class libraries and single console app) all have build tabs like this:
What can possibly be still wrong?
EDIT:
I also checked the Fusion log viewer, the AsyncCtpLibrary is loaded without any error:
*** Assembly Binder Log Entry (6/10/2011 # 9:04:11 PM) ***
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = WIN-N74LV38NLV3\Daver
LOG: DisplayName = AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
(Fully-specified)
LOG: Appbase = file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyApp.exe
Calling assembly : MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/AsyncCtpLibrary.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: Binding succeeds. Returns assembly from C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll.
LOG: Assembly is loaded in default load context.
I also checked the IL code of the <Execute>d__1c compiler-generated class' MoveNext() method, and the only assemblies it references ([assemblyName]) are mscorlib, System.Core, and AsyncCtpLibrary.
I checked the manifest of both my dll and AsyncCtpLibrary, mine said .corflags 0x00000003 // ILONLY 32BITREQUIRED, AsyncCtpLibrary said .corflags 0x00000009 // ILONLY, I'm unsure if this can be the problem.
Please help, I'm out of ideas!
EDIT: I've heard back from the compiler team, who have confirmed it as a bug. It had already been fixed in their codebase, so hopefully we'll see that fix in the next release / beta / CTP. The fix isn't going to be back-ported to "normal" VS2010 as it's a pretty unusual set of circumstances, at least before async.
EDIT: Okay, I've now got a really short but complete program which demonstrates the problem. I believe it's a mixture of generics and calling a base method:
using System;
using System.Threading.Tasks;
public abstract class AsyncAction<T>
{
public virtual Task<T> Execute()
{
// We never get this far
Console.WriteLine("Execute called");
return null;
}
}
public class BoolAction : AsyncAction<bool>
{
public async override Task<bool> Execute()
{
return await base.Execute();
}
}
class Test
{
static void Main()
{
BoolAction b = new BoolAction();
b.Execute();
}
}
EDIT: Okay, I've come up with a workaround. Basically, to call the base class method non-virtually, the compiler creates a synthetic method in BoolAction. It gets that slightly wrong, but we can get it right:
public class BoolAction : AsyncAction<bool>
{
public async override Task<bool> Execute()
{
return await BaseExecute();
}
private Task<bool> BaseExecute()
{
return base.Execute();
}
}
So whenever you were writing base.Execute, write BaseExecute and insert that extra method. It's not too bad a workaround, until the team fix the bug.
EDIT: I've simplified the example a bit - you don't need any overrides, and in particular you don't need the base class to expose a Task<T>. A call to any virtual base.Foo method will do it:
public abstract class AsyncAction<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class BoolAction : AsyncAction<bool>
{
#pragma warning disable 1998 // We're not awaiting anything
public async void Execute()
{
base.GetT();
}
#pragma warning restore 1998
}
class Test
{
static void Main()
{
BoolAction b = new BoolAction();
b.Execute();
}
}
EDIT: Contrary to my previous thoughts, this does affect iterators as well. No async CTP required...
public abstract class Base<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class Derived : Base<bool>
{
public System.Collections.IEnumerator Foo()
{
base.GetT();
yield break;
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
d.Foo().MoveNext();
}
}
EDIT: And it affects anonymous functions too...
using System;
public abstract class Base<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class Derived : Base<bool>
{
public void Foo()
{
Action x = () => base.GetT();
x();
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
d.Foo();
}
}
You are hitting known VS 2010 bug
https://connect.microsoft.com/VisualStudio/feedback/details/626550/badimageformatexception-on-simple-program-using-generics-and-lambdas
This exception often occurs when you try and load a 32 bit DLL in a 64 bit environment.
If you are running on a 64 bit OS try changing your projects settings to compile directly for x86 (rather than AnyCPU).
(This might sound backwards, but it's because if you are loading an external 32 bit DLL you need to force your whole project to be 32 bit.)

Resources