Passing a delegate as a type parameter and using it throws error CS0314
Asked Answered
V

3

8

I'm trying to pass a delegate type as a type parameter so that I can then use it as a type parameter later on in the code, like so:

// Definition
private static class Register
{
  public static FunctionObject Create<T>(CSharp.Context c, T func)
  {
    return new IronJS.HostFunction<T>(c.Environment, func, null);
  }
}

// Usage
Register.Create<Func<string, IronJS.CommonObject>>(c, this.Require);

However, the C# compiler complains:

The type 'T' cannot be used as type parameter 'a' in the generic type or method
'IronJS.HostFunction<a>'. There is no boxing conversion or type parameter
conversion from 'T' to 'System.Delegate'."

I attempted to fix this by appending "where T : System.Delegate" to the function, however, you can't use System.Delegate as a restriction on type parameters:

Constraint cannot be special class 'System.Delegate'

Does anyone know how to resolve this conflict?

DOESN'T WORK (Argument and return type information is lost during cast):

Delegate d = (Delegate)(object)(T)func;
return new IronJS.HostFunction<Delegate>(c.Environment, d, null);
Verdi answered 29/5, 2011 at 11:7 Comment(7)
Why does your solution contain a (T)?Gamez
@Gabe: It was the type that is passed in Create<T>. Unfortunately the proposed solution doesn't work at runtime.Verdi
Can you show the code for the proposed solution that doesn't work and explain how it doesn't work?Gamez
@Gabe: I added it back to the post.Verdi
I don't understand how casting an object can lose information. What does "Argument and return type information is lost during cast" mean? How do you know? Do you get an actual error message?Gamez
When IronJS goes to retrieve the argument and parameter information for the delegate, it can no longer find it (due to the cast or the fact that HostFunction has Delegate as the type parameter instead of the actual delegate).Verdi
OK, the problem is HostFunction<Delegate>, not the cast.Gamez
G
6

If you look at https://github.com/fholm/IronJS/blob/master/Src/IronJS/Runtime.fs you'll see:

and [<AllowNullLiteral>] HostFunction<'a when 'a :> Delegate> =
  inherit FO
  val mutable Delegate : 'a

  new (env:Env, delegateFunction, metaData) =
  {
      inherit FO(env, metaData, env.Maps.Function)
      Delegate = delegateFunction
  }

In other words, you cannot use C# or VB to write your function because it requires using System.Delegate as a type constraint. I recommend either writing your function in F# or using reflection, like this:

public static FunctionObject Create<T>(CSharp.Context c, T func)
{
  // return new IronJS.HostFunction<T>(c.Environment, func, null);
  return (FunctionObject) Activator.CreateInstance(
    typeof(IronJS.Api.HostFunction<>).MakeGenericType(T),
    c.Environment, func, null);
}   
Gamez answered 31/5, 2011 at 15:25 Comment(2)
Activator.CreateInstance<IronJS.Api.HostFunction<T>>(c.Environment, func, null); should work too, no? Also, good catch on the F# constraint :)Vaquero
@leppie: The same thing that prevents new from working will also prevent Activator.CreateInstance from working.Gamez
I
1

@Gabe is completely right, it has to do with the type constraint on the HostFunction<'a> class that is only valid in F# (and not C# or VB).

Have you checked the functions in Native.Utils? It's what we use internally in the runtime to create functions from delegates. Especially the let CreateFunction (env:Env) (length:Nullable<int>) (func:'a when 'a :> Delegate) = function should do exactly what you need.

If CreateFunction doesn't fulfill what you need, open a ticket at http://github.com/fholm/IronJS/issues with what you're missing and how you'd like to see it implemented and we'll get right on it.

Illstarred answered 7/6, 2011 at 20:26 Comment(1)
It's not only valid in F#. It's valid in any .NET language that hasn't intentionally <strike>crippled</strike> restricted type constraints.Odessaodetta
G
0

As an update to anyone reading this after May 2018:

As of c# 7.3 (.Net Framework 4.7.2), it is now possible to use where T : System.Delegate as a constraint on a generic declaration, which means that the original poster would now be able to do what she was trying to do in c# - without having to resort to building the class with another .Net language.

System.Enum (another sorely-missed constraint in earlier versions of c#) is now available too. There are a couple of other additions as well.

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters#delegate-constraints

Gey answered 16/5, 2019 at 1:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.