views:

93

answers:

2

I want to box a value without using whatever .NET language's built-in support for that.

That is, given an enum value I want an reference type object that represents that value and its type.

This is a subgoal of being able to pass enum values from late binding pure C++ code, a possible solution of that, so, I'm not looking for how to use e.g. C# boxing (that's easy, and irrelevant in so many ways).

The following code yields ...

c:\projects\test\csharp\hello\main.cs(6,26): error CS0122: 'System.Reflection.RuntimeFieldInfo' is inaccessible due to its protection level

However, using the more documented FieldInfo class, which is what the signature of MakeTypedReference requires, I get an exception saying that the argument isn't RuntimeFieldInfo.

The unsuccessful code, experimental, C#:

using System.Windows.Forms;
using Type = System.Type;
using TypedReference = System.TypedReference;
using MethodInfo = System.Reflection.MethodInfo;
using FieldInfo = System.Reflection.FieldInfo;
using RuntimeFieldInfo = System.Reflection.RuntimeFieldInfo;

namespace hello
{
    class Startup
    {
        static void Main( string[] args )
        {
            Type        stringType      = typeof( string );
            Type        messageBoxType  = typeof( MessageBox );
            Type        mbButtonsType   = typeof( MessageBoxButtons );
            Type        mbIconType      = typeof( MessageBoxIcon );
            Type[]      argTypes        = { stringType, stringType, mbButtonsType };// }, mbIconType };
            MethodInfo  showMethod      = messageBoxType.GetMethod( "Show", argTypes );

//          object      mbOkBtn         = (object) (MessageBoxButtons) (0);
            TypedReference tr           = TypedReference.MakeTypedReference(
                mbButtonsType,
                new RuntimeFieldInfo[]{ mbIconType.GetField( "OK" ) }
                );
            object      mbOkBtn         = TypedReference.ToObject( tr );

            object[]    mbArgs          = { "Hello, world!", "Reflect-app:", mbOkBtn };

            showMethod.Invoke( null, mbArgs );
        }
    }
}

An answer that helps making the above code "work" would be very nice.

An answer that points out another way to achieve boxing (perhaps the above is completely and utterly wrong? - it's just experimental) would also be very nice! :-)

EDIT: Clarification: essentially I'm after the same as C# (object)v yields. I have tried the enum ToObject method, but unfortunately while that presumably works OK within .NET, on the C++ side I just get back the 32-bit integer value. The problem on the C++ side is that passing an integer as third arg of e.g. MessageBox.Show just fails, presumably because the default binder on the .NET side doesn't convert it to enum type, so I suspect a reference object of suitable type is needed for actual argument.

+3  A: 

I'm not sure exactly what sort of boxing you want, but if you want a TypedReference, just use __makeref() in C#. Here's a working version of your program:

using System.Windows.Forms;
using System;
using MethodInfo = System.Reflection.MethodInfo;

namespace hello
{
    class Startup
    {
        static void Main(string[] args)
        {
            Type stringType = typeof(string);
            Type messageBoxType = typeof(MessageBox);
            Type mbButtonsType = typeof(MessageBoxButtons);
            Type[] argTypes = { stringType, stringType, mbButtonsType };
            MethodInfo showMethod = messageBoxType.GetMethod("Show", argTypes);

            var OkBtn = MessageBoxButtons.OK;
            TypedReference tr = __makeref(OkBtn);
            object mbOkBtn = TypedReference.ToObject(tr);

            object[] mbArgs = { "Hello, world!", "Reflect-app:", mbOkBtn };

            showMethod.Invoke(null, mbArgs);
        }
    }
}
Gabe
+1 for teaching me something new! :-) However it's still an intrinsic, isn't it? I'll try to delve into it, but I'm really after some language-independent way that I can use from a pure not-.NET not-C++/CLI pure standard C++ program. It is for learning purposes. Hence the upvote, I learned! :-) Thanks,
Alf P. Steinbach
+1  A: 

You may be looking for the hidden keyword '__makeref' rather than TypedReference.MakeTypedReference

var v = MessageBoxButtons.OK;
var tr = __makeref(v);
var obj = TypedReference.ToObject(tr);
var s = obj.ToString();

//  s = "OK"
Courtney de Lautour
+1 for teaching me something new. :-) see my comment to @Gabe.
Alf P. Steinbach