lundi 3 février 2020

Converting a variadic function to a System.Action using Delegate.CreateDelegate

Some background - I am writing interop between C# and another programming language and need to convert a function representation from one to another. let's say for the sake of this discussion that language is called Taco

Now - I have a situation where I need to generate a System.Action<object, object, ...> (each template argument is object because the other language is dynamically typed). I know the length at runtime.

Here is what I am trying:

    internal class VariadicAction
    {
        private TacoFuncPtr FuncPtr { get; set; }

        internal VariadicAction(TacoFuncPtr ptr)
        {
            FuncPtr = ptr;
        }

        internal void Run(params object[] varArgs)
        {
            //convert each item in varArgs to taco objects
            //call FuncPtr with them.
            var numArgs = varArgs.Length;
            var tacoArgs = new TacoArgs[numArgs];
            //convert varArgs to taco
            var tacoResult = FuncPtr.Invoke(tacoArgs);
        }
    }

    //converts Taco functions to C# Action so that they can be passed to C# functions which take a
    //System.Action as an argument.  Clients call it by passing in a System.Action with the right 
    //number of generic parameters
    class TacoFunctionConverter
    {
        static bool TryConvertTacoFunctionToCSharp<T>(TacoObject tacoFunctor, out T value)
        {
            value = default(T)
            var tT = typoeof(T);
            //lets say this returns the number of arguments from C#, requires it to be a System.Action
            var numArgs = GetNumArgs(tT);
            if (GetNumArgs(tacoFunctor) != numArgs) return false;

            //construct a System.Action<object,...> variadically!
            var genericActionType = typeof(Action<>);
            Type[] types = Enumerable.Repeat(typeof(object), numArgs).ToArray();
            var constructedActionType = genericActionType.MakeGenericType(types);
            Delegate del = Delegate.CreateDelegate(constructedActionType, variadicAction, "Run", false);
            actionObj = (object)del;
            value = (T)actionObj;
            return true;
        }
    }

When I do this I get the following exception: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

My question is, am I on the right track? I also tinkered with using a lambda but got even less far with that approach.





Aucun commentaire:

Enregistrer un commentaire