Why does this line cause a VerificationException when running under .NET 4? - c#

Help me out folks - why does this code cause a VerificationException when run under .NET 4.0?
public T parseEnum<T>(string value, T defaultValue) {
//Removing the following lines fixes the problem
if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
return defaultValue;
}
I ran peverify on the .net 2.0 assembly and got the following message:
ImageResizer.Util.Utils::parseEnum[T]][offset 0x0000000A] The 'this' parameter to the call must be the calling method's 'this' parameter.
This causes a VerificationException: Operation could destabilize the runtime message when running the code under medium trust.
I've already read all the similar-looking posts on stack overflow, and none of them apply to this code.
Is there something new with generics that would cause this code to be somehow invalid?

The underlying reason for the error is a change in the signature of IsEnum.
In .NET 2.0 (and 3.0), IsEnum wasn't a virtual method:
public bool IsEnum { get; }
The assembly emitted to call it is:
call instance bool [mscorlib]System.Type::get_IsEnum()
In .NET 4.0, IsEnum is a virtual method:
public virtual bool IsEnum { get; }
Here is the same line of assembly for 4.0:
callvirt instance bool [mscorlib]System.Type::get_IsEnum()
The error you're getting was added in peverify just before the 2.0 release, and warns when a virtual method is called non-virtually.
Now, peverify loads up your code, loads .NET 4.0, and then checks your code. Since your code calls the (.NET 4.0) virtual method non-virtually, the error is shown.
One would think that since you're building against the .NET 2.0 version, this should be fine, and it would load the .NET 2.0 CLR to check. It doesn't seem so.
Edit:
In order to check this, I downloaded .NET 2.0's SDK and tried the peverify in there. It correctly verifies the code.
So the message would seem to be this: use a peverify which matches the target framework of your code.
Solution:
It seems that the _Type interface provides a solution to this:
if (((_Type)typeof(T)).IsEnum) ...
The documentation says it is designed to be called from unmanaged code, but as a side effect of it being an interface, it provides a stable (virtual) method to call.
I have confirmed that it works with peverify whether you target 2.0 or 4.0.

Related

XmlSerializer behaves different with a property's private getter on .net framework and .net core

I've consumed a third party nuget package which supported .net core and .net framework (.net standard).
My project was a .net framework 4.62 project and when I've used that third party, I've received an exception from the XmlSerializer.
The problem was due to a private getter in a property.
Only public properties and fields can be serialized. Properties must have public accessors (get and set methods). If you need to serialize non-public data, use the BinaryFormatter class rather than XML serialization.
Full Source
After receiving that error, I tried to open a .net core 2.2 project, consumed the same third party nuget and saw that the same code worked there.
He is a small example of code that reproduces the issue:
public class Test
{
public string TestProp { private get; set; }
}
// Exception on .net 462 and works on .net core 2.2
var serializer = XmlSerializer.FromTypes(new[] { typeof(Test) });
So, is this a bug on the .net core implementation or a feature?
Is there anything I can do rather to support this on .net framework without forking the repo and fixing the code?
The "bug" here is that it fails at a different time; on net462 it fails during FromTypes; on netcoreapp2.2 and netcoreapp3.0, it fails during the Serialize, with:
System.InvalidOperationException: There was an error generating the XML document.
---> System.MethodAccessException: Attempt by method 'Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterTest.Write2_Test(System.String, System.String, Test, Boolean, Boolean)' to access method 'Test.get_TestProp()' failed
So ... it really isn't worth worrying about, IMO. There is no real feature difference, by which I mean: it isn't going to work either way. So just... don't do that?
But: you could log it as a bug on github, and even submit a PR so that it fails earlier, if you really want.
That said: if you add:
public bool ShouldSerializeTestProp() => false;
then it will actually work on netcoreapp2.2 and netcoreapp3.0, which is... nice I guess? And could even be considered a reason not to change the new behavior.

How can I this fix covariance issue with Action on .NET 2?

I need to create a covariant interface with a method that takes a delegate with covariant generic parameter. Here's the code sample under question:
interface IExample<out T1>
{
void ExampleMethod(Action<T1> someAction);
}
On Mono/ .NET 4 profile it compiles OK (tested it in Xamarin studio). However, on .NET 2 (which I'm forced to use since I'm using Unity game engine), I get the following error:
error CS1961: The covariant type parameter 'T1' must be invariantly valid on `CovarianceExample.IExample.ExampleMethod(System.Action)'
Why does this error occur in early .Net versions? How can I fix it?
Why does this error occur in early .Net versions?
Because Action wasn't contravariant in .NET 2.0 (or 3.5).
How can I fix it?
Don't use .NET 2.0 :) I thought that modern versions of Unity were based on more recent versions of Mono anyway - perhaps an upgrade is available?
Alternatively, you could declare your own ContravariantAction delegate:
public delegate void ContravariantAction<in T>(T value);
I haven't tried doing so against .NET 2.0, but I believe the appropriate attributes were already present, and at least the MS .NET implementation supported generic variance - it just wasn't exposed in C# or used in the BCL.

How Can I Force .NET (C#) to Use the non-generic overload of a method?

There's a method in the .NET Framework that has both generic and a non-generic version/overload. I want to force the compiler to generate my code using the non-generic version even if it can resolve the generic type at build time.
The specific method I want to use is Marshal::GetFunctionPointerForDelegate which, as of .NET 4.5.1, has a generic overload. I want to use the original one (non-generic).
Also, if you could provide the solution (if any) in C++/CLI, it'd be much appreciated.
UPDATE: There reason for this is that, if my program is ran in a computer that does not have .NET 4.5.1, my program will crash.
It should be clear from the source code snippet posted by #elgonzo that the generic version is calling the non-generic version, otherwise you would have infinite recursion.
Therefore, you too can call the non-generic version. The trick is making the non-generic version a perfect match.
C#:
Marshal.GetFunctionPointerForDelegate( (Delegate)(object) mydel );
C++/CLI:
Marshal::GetFunctionPointerForDelegate( dynamic_cast<Delegate^>(safe_cast<Object^>(mydel)) );
It does not really matter whether you use the generic or the non-generic variant of the Marshall.GetFunctionPointerForDelegate method.
The only thing Marshall.GetFunctionPointerForDelegate<TDelegate>(...) does is calling the non-generic Marshal.GetFunctionPointerForDelegate(...) method.
As can be seen in the .NET framework reference source code, the implementation of GetFunctionPointerForDelegate<TDelegate> is just:
public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d)
{
return GetFunctionPointerForDelegate((Delegate)(object)d);
}
Regarding your update
UPDATE: There reason for this is that, if my program is ran in a computer that does not > have .NET 4.5.1, my program will crash.
Set the target framework of your project to a .NET version prior to 4.5.1 (for example, if your project is required to run on .NET 3.5, then set the target framework of your project to .NET 3.5.)

SecurityException: ECall methods must be packaged into a system module

I have a (C#) function similar to the following.
private static bool SpecialCase = false;
public void Foo()
{
if (SpecialCase)
{
InternalMethod();
return;
}
Console.WriteLine();
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void InternalMethod();
When I execute this with the .NET Framework 4 inside the debugger, the method successfully prints blank line to the console and returns. When I execute it outside the debugger, it throws an exception with the following message:
System.Security.SecurityException: ECall methods must be packaged into a system module.
It appears the exception is thrown when the JIT compiler compiles the method as opposed to when (if) InternalMethod is called. Is there anything I can do (e.g. attributes) to tell the CLI to either not throw the SecurityException, or delay the exception until the method is actually called?
Side note on the use case: The SpecialCase field is effectively false when running with Microsoft .NET Framework, and true when running under a different (specific) implementation of the CLI. When running under the Microsoft .NET Framework, the call to InternalMethod is effectively unreachable.
Add attribute [ComImport] to your class declaration
You may want to check the compiler directives as a possible option.
Unlike using a run-time "if", this will determine whether the call is included in the compiled code at all, rather than always compiling it into the code and trying to determine whether to call it at run-time (which is too late, based on your analysis).
Your use-case seems like a testing/validation scenario, which means that you don't need it compiled into the code except when the internal call will actually be made.
Note that if your use-case involves a non-.NET runtime, you should provide more information since that could drastically change the correct answer.

Using LinqBridge in .Net2.0 Website

has anyone been able to use Linqbridge on a .Net 2.0 Website?
I have no problem using it in a normal .Net 2.0 console, but when I use the methods in the website,
I get
Feature 'extension method' cannot be used because it is not part of the ISO-2 C# language specification
I think the error message is pretty clear. Extension methods aren't supported in 2.0. If you want to use an extension method in 2.0, you'd need to modify it by removing the this and call it explicitly.
If you had:
public static class ExtensionMethods {
public static bool IsOdd(this int x) {
return x % 2 != 0;
}
}
Then ExtensionMethods and code like number.IsOdd() won't compile.
You'd need to remove the this in the IsOdd method signature and call it as ExtensionMethods.IsOdd(number) to get it to work under 2.0.
If I recall correctly, that's the approach the authors of LinqBridge used.
Hope that helps.
Maybe you're confusing .NET and C# versions. LINQBridge supports .NET 2.0, but you still need C# 3.0 or later (i.e. VS2008 or later) to compile code with extension method or LINQ syntax sugar. Once compiled, the assembly runs without issue on .NET 2.0 runtimes. That's the benefit of LINQBridge.

Categories

Resources