VARIANT datatype of C++ into C#

kamal picture kamal · Apr 4, 2013 · Viewed 15.9k times · Source

What is equivalent of the VARIANT datatype of C++ in C#?

I have code in C++ which uses the VARIANT datatype. How can I convert that code in C#?

Answer

atlaste picture atlaste · Apr 11, 2013

Well, there are actually two variant's in C++: boost::variant and COM variant. The solution follows more or less the same idea, but the former is more complex. I expect you mean to use the latter.

Let me first start by telling that this is something you just shouldn't use if possible. That said, this is how you do it :-)

Variants and interop

Variants are sometimes used in interop of if you need the byte representation to be the same.

If you're dealing with interop, make sure to check out the VariantWrapper class on MSDN and make it work like that.

Variants and porting considerations

Variants are mostly used in APIs, and usually like this:

void Foo(SomeEnum operation, Variant data);

The reason it's done like this in C++ is because there is no base object class and you therefore need something like this. The easiest way to port this is to change the signature to:

void Foo(SomeEnum operation, object data);

However, if you're porting anyway, you also seriously want to consider these two, since they are resolved at compile-time and can save you the big 'switch' that usually follows in method Foo:

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

Variants and byte consistency

In rare cases you need to manipulate the bytes themselves.

Essentially the variant is just a big union of value types wrapped in a single value type (struct). In C++, you can allocate a value type on the heap because a struct is the same as a class (well sort-of). How the value type is being used is just a bit important but more on that later.

Union simply means you are going to overlap all the data in memory. Notice how I explicitly noted value type above; for variant's this is basically what it's all about. This also gives us a way to test it - namely by checking another value in the struct.

The way to do this in C# is to use the StructLayout attribute in a value type, which basically works as follows:

[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's can also be stored on the heap as I noted earlier. If you do this, you probably still want the memory signature to be the same. The way to do this is to box the Variant struct we build earlier by simply casing it to object.