3

我想在不使用任何 .NET 语言的内置支持的情况下对值进行装箱。

也就是说,给定一个枚举值,我想要一个表示该值及其类型的引用类型对象。

这是能够从后期绑定纯 C++ 代码中传递枚举值的子目标,这是一个可能的解决方案,因此,我不是在寻找如何使用例如 C# 装箱(这很容易,并且在很多方面都无关紧要)。

以下代码产生...

c:\projects\test\csharp\hello\main.cs(6,26): error CS0122: 'System.Reflection.RuntimeFieldInfo' 由于其保护级别而无法访问

但是,使用更多记录的FieldInfo类,这是签名所MakeTypedReference要求的,我得到一个异常,说参数不是RuntimeFieldInfo.

不成功的代码,实验性的,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 );
        }
    }
}

有助于使上述代码“工作”的答案会非常好。

指出另一种实现拳击的方法的答案(也许以上完全和完全错误? - 这只是实验性的)也将非常好!:-)

编辑:澄清:基本上我和C#(object)v产量一样。我已经尝试过 enumToObject方法,但不幸的是,虽然这在 .NET 中可能工作正常,但在 C++ 端,我只取回 32 位整数值。C++ 方面的问题是,将整数作为 eg 的第三个参数传递会MessageBox.Show失败,大概是因为 .NET 方面的默认绑定器不会将其转换为枚举类型,所以我怀疑需要一个合适类型的引用对象实际论证。

4

3 回答 3

7

我不确定你想要什么样的拳击,但如果你想要一个TypedReference,只需__makeref()在 C# 中使用。这是您的程序的工作版本:

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);
        }
    }
}
于 2010-10-25T03:34:36.013 回答
3

您可能正在寻找隐藏的关键字 '__makeref' 而不是 TypedReference.MakeTypedReference

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

//  s = "OK"
于 2010-10-25T03:35:34.343 回答
0

任何可以采用某种类型的例程Object都可以用于存储值类型,而无需使用框架的装箱支持,方法是为要存储的每个值类型实例创建一个单元素数组,并存储对它的引用。编译器可以Debug.Print通过特殊声明来支持需要接受可变数量的任意类型参数的事情,该声明将要求编译器传递 a System.Array[],其中的每个元素都是一个单元素数组,它包装了一个参数而不考虑无论是类类型还是值类型。如果存在这样的支持,那么例程就有可能Debug.Print知道每个参数的存储位置类型以及其中的对象实例的类型(例如,在类似的代码中)

Cat Meowser = new SiameseCat();
Animal Ralph = new PersianCat();
IPettable Mindy = new MixedBreedCat();
Debug.Print("{0:T} {1:T} {2:T}", Meowser, Ralph, Mindy);

Debug.Print例程将接收对 a 、 an和 an的System.Array[3]持有引用。Cat[1]Animal[1]IPettable[1]

请注意,如果没有装箱支持,实现接口的结构不能直接转换为接口引用;这有时会是一种限制,但施加这种限制可以使值类型可以定义与接口类型之间的转换。如果需要,编译器可以为每个实现接口的结构类型自动定义一个类类型,并定义结构类型和该接口类型之间的转换。除了与每个值类型相关联的引用类型是在运行时而不是由编译器生成的之外,类型系统实际上会发生这种情况。

于 2013-06-08T18:22:11.353 回答