June
June

Reputation: 3307

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

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);

Upvotes: 8

Views: 2341

Answers (3)

Daniel Scott
Daniel Scott

Reputation: 1878

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

Upvotes: 0

thr
thr

Reputation: 19476

@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.

Upvotes: 1

Gabe
Gabe

Reputation: 86718

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);
}   

Upvotes: 6

Related Questions