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.
Related
When I use float.IsFinite(float f) in a C# shell, I have no problems. However, when I use it in the context of Unity, I get an error alleging that it is not defined:
Here is the relevent code:
public static bool IsFinite(Unit u) => float.IsFinite(u.blocks);
Unit is a struct in which I wrote the above line.
My question is: why does this error appear and how can I fix it?
float.IsFinite exists in .NET 5, .NET Standard 2.1 and .NET Core 2.1. However Unity supports neither of those frameworks, just .NET Standard 2.0. This is why you cannot use the function here.
However it´s easy to create a workaround for the lack of that function:
public static bool IsFinite(Unit u) => !float.IsInfinity(u.blocks)
There´s an angoing discussion at Unitity support forum about .NET 5
I discovered this method (Type.IsAssignableFrom) which would come in very handy, but VS (for Mac, Xamarin Forms project) labels it a missing method. (I get the red squigly) Is it deprecated or missing for the .Net version that works with Xamarin or something?
This is the code, which I got from msdn:
public class Example
{
public static void Main() {
Type t = typeof(IEnumerable);
Type c = typeof(Array);
IEnumerable instanceOfT;
int[] instanceOfC = { 1, 2, 3, 4 };
if (t.IsAssignableFrom(c))
instanceOfT = instanceOfC;
}
}
Since a Xamarin.Forms project is a Portable Class Library with multiple target frameworks, you can only use stuff that exists in all the targets.
MSDN article that might give more information:
With the advent of .NET Native, we have a technology that allows us to
statically link your application with the framework and third party
dependencies. For the linking to be viable, it’s important that it can
identify the parts of the framework that you’re not using. In other
technologies, such as C++, this is somewhat straightforward as these
systems don’t have dynamisms such as reflection. Of course, .NET
Native still supports reflection but we wanted to make the platform
more pay-for-play friendly, meaning that you don’t have to pay for
features that you don’t use. This is especially true for reflection,
as it imposes significant constraints on what the runtime and
compilers can do based on static information.
So ideally, reflection should be an optional component in .NET Core
that you might decide not to use in your application at all. The
tricky part is that System.Object has a dependency on reflection via
Object.GetType(). In order to break that dependency, we decided that
System.Type no longer represents the full-blown reflection type
information but only the type name. This means that System.Type in
.NET Core no longer contains APIs such as GetMembers(), but continues
to expose APIs such as Name.
In order to get access to the additional type information you have to
invoke an extension method called GetTypeInfo() that lives in
System.Reflection. It returns the new type TypeInfo which is what Type
used to be.
So you should be doing it like this:
if (t.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()))
Removing the .NET Core target from the project should also work.
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.)
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.
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.