views:

270

answers:

2

I'm trying to create a delegate of a static method which takes a ref argument. Please don't ask why I'm doing such a cockamamie thing. It's all part of learning how .Net, C#, and reflection work and how to optimize it.

My code is:

    public struct DataRow
    {

        private double t;
        static public void Cram_T(ref DataRow dr, double a_t)
        {
            dr.t = a_t;
        }
    }
 ''''
  Type myType = typeof(DataRow);
  MethodInfo my_Cram_T_Method = myType.GetMethod("Cram_T");
  var myCram_T_Delegate = 
         Delegate.CreateDelegate(typeof(Action<DataRow, Double>),      
                                 my_Cram_T_Method) 
                                 as Action<DataRow, Double>;

This gives me a binding error because (I think) the generic action doesn't match the method.

Inspecting the value of Cram_T_Method in the watch window gives

{Void Cram_T(DataRow ByRef, Double)}

I then tried using the ref keyword in the Action:

  var myCram_T_Delegate = 
         Delegate.CreateDelegate(typeof(Action<ref DataRow, Double>),         
                                 my_Cram_T_Method) 
                                 as Action<ref DataRow, Double>;

But this won't compile. The C# compiler chokes at the token "ref".

What is the right way to create this delegate?

+3  A: 

Create your own delegate type:

delegate void MyAction(ref DataRow dataRow, double doubleValue);

And use MyAction in place of Action<ref DataRow, Double> -- which, as you've noted, doesn't compile.

Ben M
+2  A: 

@Ben M has the right idea, although you could make it more generic:

public delegate void RefAction<T1, T2>(ref T1 arg1, T2 arg2)

The problem has nothing to do with delegates as such - it's just that you can't use ref when you specify a type argument.

In theory the "it's by ref or not" is part of the type information (hence Type.IsByRef) but you can't specify it like that.

Frankly I'm not at all sure what would happen if you tried to create a List<ref int> via reflection, for example - I would hope that an exception would be thrown... it's not a very sensible concept :)

EDIT: I've just tried it:

Type refInt = typeof(int).MakeByRefType();
Type refIntList = typeof(List<>).MakeGenericType(refInt);

Throws an error:

Unhandled Exception: System.ArgumentException: The type 'System.Int32&' may
not be used as a type argument.
Jon Skeet
Type arguments must be types whose values are convertible to object. Managed and unmanaged pointer types don't meet that requirement.
Eric Lippert
Well I never. Fascinating. For once, I *don't* think it'll be worth including that in C# in Depth. Maybe as a note...
Jon Skeet
This works but the list commentary is irrelevant. public delegate void RefGenAction<T1, T2>(ref T1 arg1, T2 arg2); var myCram_TDelegate = Delegate.CreateDelegate(typeof(RefGenAction<DataRow, Double>), myType.GetMethod("Cram_T")) as RefGenAction<DataRow, Double>;
Max Yaffe
@Max Yaffe: In what way is the list commentary irrelevant? It's making the point that you can never use "ref Foo" as a generic type argument, whether it's for a delegate or not.
Jon Skeet