2013-04-04 17 views
8

C#のVARIANTデータ型に相当するものは何ですか?C++のVARIANTデータ型をC#

私はVARIANTデータ型を使用するC++のコードを持っています。 C#でそのコードをどのように変換できますか?

+0

C++コードと相互運用する必要がありますか、コードを変換するだけですか? – Botz3000

+3

直接の等価物は型として 'object'であり、" variantには何が入っていますか "のような' object.GetType() 'です。しかし、それは本当に貧弱なC#コードを作るでしょう。文脈は重要です。 – Jon

+0

C#4.0を使用している場合は、 'dynamic'データ型を使用できますが、@ Jonは言っているように、タイプセーフティとコンパイル時のチェックを回避するため、C#コードが貧弱になります。 –

答えて

1

これは難しい質問です。

C#4では、ダイナミックを使用して、実行時にその型がわかっていることを示すことができます。

私の個人的な理解では、しかし、C++はコンパイル時に知られている型を必要とします。したがって、objectを使用することも考えられますが、C#のobjectは既存のタイプです。

VARIANTの(AKA多型)のマルチタイプのコンセプトについては、C#で対応するタイプを見つける必要はなく、クラスとインターフェースを定義するだけです。クラスを実装するインタフェースとして、オブジェクトを常に参照できます。

コードを移植していて、単純にLHSで使用できる構文を理解し、コンパイル時に型の考慮がわかっている場合は、varを使用します。

7

実際、C++にはboost :: variantとCOM variantの2種類があります。この解決方法は、ほぼ同じ考え方に従いますが、前者はより複雑です。私はあなたが後者を使うことを意味すると思います。

まず、可能な限り使用しないでください。それは言った、これはあなたがそれを行う方法:-)

変異体および相互運用

変異体は、時々あなたが同じになるようにバイト表現が必要な場合の相互運用に使用されています。

interopを扱う場合は、MSDNのVariantWrapperクラスをチェックして、そのように動作させるようにしてください。

変異体および移植の考慮

変異体は、ほとんどのAPIで使用され、通常はこのようにしている:なしベースobjectクラスが存在しないため

void Foo(SomeEnum operation, Variant data); 

それはC++で次のように行うの理由があるとしたがって、このようなものが必要です。とにかく移植している場合は、あなたも真剣に彼らは、コンパイル時に解決されて、あなたを救うことができるので、これら2、検討する必要が

void Foo(SomeEnum operation, object data); 

:ポートへの最も簡単な方法は、これはに署名を変更することです通常の方法Fooに次の大きな「スイッチ」:まれに

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

変異体およびバイト一貫

あなたはバイト自体を操作する必要があります。

本質的には、バリアントは単なる値型(構造体)にラップされた値型の大きな結合体です。 C++では、構造体がクラス(well sort-of)と同じであるため、ヒープに値型を割り当てることができます。値の型の使用方法は少し重要ですが、後でその値を増やしてください。

ユニオンとは、単にメモリ内のすべてのデータをオーバーラップさせることを意味します。上記の値の型を明示的に示したことに注目してください。バリアントについては、これは基本的にはすべてについてです。これはまた、構造体の別の値を検査することによって、それをテストする方法を提供します。 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にケーシングするだけです。

+0

@KenKinは実際に私が与えた4つのオプションのうちの1つです... – atlaste

0

もう一度元気にしましょう。遅かれ早かれ、VARIANTに実際のデータが必要です。 VARIANTは意味のあるデータの保持者に過ぎません。 VARIANTを、C#のバリアント型と.NETフードの下にあるいくつかのローバッファ(.NETの文字列では生のバッファを公開できる)のある種のObjectに変換したとします。その時点で、バリアント型は、オブジェクトと、バリアントによって指定されたデータ型に変換または変換された生データとから決定され、次いで、例えば、新しいオブジェクトを作成する必要がある。文字列/ int/etc。生データから。

VARIANTをC#に渡すことを心配するのではなく、バリアントデータ型を見て、C++で実際のデータ型に変換してC#に渡します。

VARIANT型がVT_INTある場合たとえば、その後、バリアントからint型を取得し、のようなものを使用することができます。

returnIntはC++ DLL内のC++関数からOutパラメータとして返すことができ
VARIANT var; 

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

C#から呼び出すことができます。 C++のdllは/ clrオプションを使う必要があります。

機能は次のようになります -

void ThisFunctionReturnsAnInt(Runtime::InteropServices::OutAttribute Int^ % returnIntValue) 
{ 

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

は、他のデータ型のために同様のアプローチを使用することができます。それは当然のことですが、VT_INTのVARIANTは実際にはintと似ています。主要な変換が行われているかのようにではなく、実際にVARIANTから実際の値を取り出して、あなたがC++からC#にまっすぐな整数値を渡していたとします。あなたはまだとにかくgcnewをする必要があります。

1

.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); 
     } 
    } 
} 

あなただけ

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を使用しないように注意を払うとにその所有権を与えるだろう、COMインターフェイスオブジェクトのインスタンスを指すVT_UNKNOWNにアクセスしている場合...

さらに複雑なコードの場合は、this articleと表示され、メモリ管理についても説明しています。