将c++的变量数据类型转换为c#

本文关键字:类型转换 数据 变量 c++ | 更新日期: 2023-09-27 18:07:24

c#中与c++的VARIANT数据类型等价的是什么?

我在c++中使用VARIANT数据类型的代码。我如何将代码转换为c# ?

将c++的变量数据类型转换为c#

实际上c++中有两种变体:boost::variant和COM variant。解决方案或多或少遵循相同的思想,但前者更复杂。我想你的意思是用后者。

让我首先告诉你,如果可能的话,这是你不应该使用的。也就是说,你应该这样做:-)

变量和互操作

如果您需要相同的字节表示,则有时在互操作中使用变体。

如果你正在处理互操作,请确保在MSDN上检查VariantWrapper类并使其像那样工作。

变体和移植注意事项

变量主要用于api中,通常像这样:

void Foo(SomeEnum operation, Variant data);

在c++中这样做的原因是因为没有基本的object类,因此需要这样的东西。移植它的最简单方法是将签名更改为:

void Foo(SomeEnum operation, object data);

然而,如果你无论如何都要移植,你也要认真考虑这两个,因为它们是在编译时解决的,可以节省你通常在Foo方法后面的大"切换":

void SomeOperation(int data);
void SomeOperation(float data);
// etc

变量和字节一致性

在极少数情况下,您需要操作字节本身。

本质上,该变体只是将多个值类型包装在单个值类型(struct)中。在c++中,您可以在堆上分配值类型,因为结构体与类(在某种程度上)相同。如何使用值类型是很重要的,但后面会详细介绍。

Union仅仅意味着你要重叠内存中的所有数据。请注意我是如何在上面明确指出值类型的;对于变体来说,这基本上就是它的全部内容。这也为我们提供了一种测试方法——即检查结构体中的另一个值。

在c#中做到这一点的方法是在值类型中使用StructLayout属性,其基本工作如下:
[StructLayout(LayoutKind.Explicit)]
public struct Variant
{
    [FieldOffset(0)]
    public int Integer;
    [FieldOffset(0)]
    public float Float;
    [FieldOffset(0)]
    public double Double;
    [FieldOffset(0)]
    public byte Byte;
    // etc
}
// Check if it works - shouldn't print 0.
public class VariantTest
{
    static void Main(string[] args)
    {
        Variant v = new Variant() { Integer = 2 };
        Console.WriteLine("{0}", v.Float);
        Console.ReadLine();
    }
}
如前所述,

c++变量也可以存储在堆中。如果这样做,您可能仍然希望内存签名是相同的。这样做的方法是将我们之前构建的Variant结构框起来,只需将其封装为object

When 。. NET实现了一个COM接口,只是使用VARIANT*代替。

然后通过使用IntPtr类型来接收指针,从而绕过。net接收端的封送处理

public class ComVariant
{
    [StructLayout(LayoutKind.Sequential)]
    public struct Variant
    {
        public ushort vt;
        public ushort wReserved1;
        public ushort wReserved2;
        public ushort wReserved3;
        public Int32 data01;
        public Int32 data02;
    }
    private Variant _variant;
    private IntPtr _variantPtr;
    public ComVariant(int variantPtr) : this(new IntPtr(variantPtr))
    {
    }
    public ComVariant(IntPtr variantPtr)
    {
        _variant = (Variant)Marshal.PtrToStructure(variantPtr, typeof(Variant));
        _variantPtr = variantPtr;
    }
    public VarEnum Vt
    {
        get
        {
            return (VarEnum)_variant.vt;
        }
        set
        {
            _variant.vt = (ushort)value;
        }
    }
    public object Object
    {
        get
        {
            return Marshal.GetObjectForNativeVariant(_variantPtr);
        }
    }
}

然后如果你正在访问指向COM接口对象实例的VT_UNKNOWN,只需

var variant = new ComVariant(variantPtr);
var stream = variant.Object as IStream; // will not be null if type is correct
var obj = variant.Object as IObj; // in general...

可以做到这一点,但要注意不要使用新分配的VARIANT并将其所有权赋予.NET实现而不将其释放到某个地方…

对于更复杂的代码,您可以阅读这篇文章,它也讨论了内存管理。

这是一个棘手的问题。

从c# 4开始,可以使用dynamic来表示该类型在运行时是已知的。

根据我个人的理解,c++需要编译时已知的类型。因此,您可能会考虑使用object,但object在c#中是一个存在的类型。

对于多类型、单值(又名多态性)的概念,您不需要在c#中找到相应的类型,只需定义您的类和接口。你总是可以引用一个对象作为类实现的接口。

如果您正在移植代码,并且要找出可以简单地在LHS中使用的语法,并且考虑到编译时已知的类型,则使用var

让我们回顾一下。迟早,我们需要在VARIANT中获得实际数据。变体只是有意义的数据的保存器。假设我们将VARIANT转换为c#中的某种对象,该对象具有。net下的变体类型和一些原始缓冲区(例如。net字符串可以公开原始缓冲区)。此时,VARIANT类型需要从对象中确定,并将原始数据转换或强制转换为变体指定的数据类型,然后创建一个新对象,例如string/int/等。从原始数据

因此,与其担心将VARIANT传递给c#,不如查看变量数据类型并将其在c++中转换为实际数据类型并将其传递给c#。

例如,如果VARIANT类型是VT_INT,那么从变体中获取int,并可以使用如下内容:

VARIANT var;
Int^ returnInt = gcnew Int(var.intVal);

return可以作为Out参数从c++ dll中的c++函数返回,该函数可以从c#中调用。c++ dll需要使用/clr选项。

函数看起来像:-

void ThisFunctionReturnsAnInt(Runtime::InteropServices::OutAttribute Int^ % returnIntValue)
{
    VARIANT var;
    Int^ returnInt = gcnew Int(var.intVal);
}

可以对其他数据类型使用类似的方法。这是很自然的,VT_INT的一个变体就像一个int,它不像是有一些主要的转换在进行,你只是在你感兴趣的时候从变体中取出实际的值,就像你从c++传递一个直接的整数值到c#一样。无论如何,您仍然需要执行gcnew。