ВАРИАНТНЫЙ тип данных C ++ в C #

Что эквивалентно типу данных VARIANT C ++ в C #?

У меня есть код на C ++, который использует тип данных VARIANT. Как я могу преобразовать этот код в C #?

9

Решение

Это сложный вопрос.

Из C # 4 вы можете использовать динамический чтобы указать, что тип известен во время выполнения.

Однако, по моему личному пониманию, с ++ требует тип, известный во время компиляции. Таким образом, вы можете рассмотреть возможность использования object, но object в C # это существующий тип.

Для концепции мульти-тип, одно значение (AKA полиморфизм) VARIANT, вам не нужно находить соответствующий тип в C #, просто определите свои классы и интерфейсы. Вы всегда можете ссылаться на объект как на его интерфейс, который реализует класс.

Если вы переносите код и выясняете синтаксис, который вы можете просто использовать в LHS, и для рассмотрения типа известен во время компиляции, тогда используйте вар.

1

Другие решения

Ну, на самом деле есть два варианта в C ++: Boost :: Вариант и COM вариант. Решение следует более или менее той же идее, но первое является более сложным. Я ожидаю, что вы хотите использовать последний.

Прежде всего позвольте мне сказать, что это то, что вы просто не должны использовать, если это возможно. Тем не менее, это, как вы это делаете 🙂

Варианты и взаимодействие

Варианты иногда используются во взаимодействии, если вам нужно, чтобы байтовое представление было одинаковым.

Если вы имеете дело с взаимодействием, не забудьте проверить VariantWrapper класс на MSDN и заставить его работать так.

Варианты и соображения портирования

Варианты в основном используются в 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 ++ вы можете выделить тип значения в куче, потому что структура — это то же самое, что и класс (ну вроде). То, как используется тип значения, немного важно, но об этом позже.

Объединение просто означает, что вы собираетесь перекрывать все данные в памяти. Обратите внимание, как я явно отметил тип значения выше; для варианта это в основном то, что это все. Это также дает нам возможность проверить это, а именно, проверяя другое значение в структуре.

Способ сделать это в 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,

8

когда .NET реализует интерфейс COM, просто используйте VARIANT * вместо.

затем обходить сортировку на стороне получения .NET с помощью IntPtr введите, чтобы получить указатель.

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

тогда, если вы обращаетесь к VT_UNKNOWN, указывающему на экземпляр объекта интерфейса COM, просто

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, не освобождая его где-нибудь …

Для более сложного кода вы могли бы прочитать Эта статья который также говорит об управлении памятью.

1

Давайте сделаем шаг назад. Рано или поздно нам нужны реальные данные в VARIANT. VARIANT — это просто держатель значимых данных. Предположим, мы преобразовали VARIANT в какой-то объект в C #, который имел тип варианта и некоторый необработанный буфер под капотом .NET (например, строки .NET могут открывать необработанный буфер). На этом этапе тип VARIANT должен быть определен из объекта, а необработанные данные преобразованы или преобразованы в тип данных, указанный в варианте, а затем создать новый объект, например, строка / INT / и т.д.. из необработанных данных.

Поэтому, вместо того, чтобы беспокоиться о передаче VARIANT в C #, посмотрите на вариантный тип данных и преобразуйте его в C ++ в фактический тип данных и передайте его в C #.

Например, если тип VARIANT — VT_INT, тогда получите int из варианта и можете использовать что-то вроде:

VARIANT var;

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

returnInt может быть возвращен как параметр Out из функции C ++ в DLL C ++, которая может быть вызвана из C #. DLL C ++ должен использовать параметр / clr.

Функция будет выглядеть так:

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

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

Можно использовать аналогичный подход для других типов данных. Это естественно, VARIANT VT_INT действительно похож на int, это не так, как будто происходит какое-то серьезное преобразование, вы просто берете фактическое значение из VARIANT в тот момент, когда вы заинтересованы в нем, как вы если бы вы передавали прямое целочисленное значение из C ++ в C #. Вам все равно нужно сделать gcnew в любом случае.

0
По вопросам рекламы [email protected]