Yapı hazırlamayı özelleştirme
Bazen yapılar için varsayılan sıralama kuralları tam olarak ihtiyacınız olan şey değildir. .NET çalışma zamanları, yapınızın düzenini ve alanların nasıl düzenlendiğini özelleştirmeniz için birkaç uzantı noktası sağlar. Yapı düzenini özelleştirme tüm senaryolar için desteklenir, ancak alan sıralamasını özelleştirme yalnızca çalışma zamanı hazırlamanın etkinleştirildiği senaryolarda desteklenir. Çalışma zamanı hazırlama devre dışı bırakıldıysa, tüm alan hazırlamaları el ile yapılmalıdır.
Not
Bu makale, kaynak tarafından oluşturulan birlikte çalışma için hazırlamayı özelleştirmeyi kapsamaz. P/Invokes veya COM için kaynak tarafından oluşturulan birlikte çalışma kullanıyorsanız bkz. Sıralamayı özelleştirme.
Yapı düzenini özelleştirme
.NET, alanların belleğe yerleştirilme şeklini özelleştirmenize olanak sağlamak için özniteliğini ve System.Runtime.InteropServices.LayoutKind numaralandırmasını sağlarSystem.Runtime.InteropServices.StructLayoutAttribute. Aşağıdaki kılavuz yaygın sorunlardan kaçınmanıza yardımcı olacaktır.
✔️ Mümkün olduğunda kullanmayı LayoutKind.Sequential
GÖZ ÖNÜNDE BULUNDURUN.
✔️ DO, yalnızca LayoutKind.Explicit
yerel yapınızda birleşim gibi açık bir düzen olduğunda kullanılır.
❌ Devralma yoluyla karmaşık yerel türleri ifade etmek için sınıfları kullanmaktan KAÇıNıN.
❌ .NET Core 3.0'ın öncesinde çalışma zamanlarını hedeflemeniz gerekiyorsa, Windows dışı platformlarda yapıları derlerken kullanmaktan LayoutKind.Explicit
KAÇıNıN. 3.0 öncesi .NET Core çalışma zamanı, Intel veya AMD 64 bit Windows olmayan sistemlerde yerel işlevlere değere göre açık yapıların geçirilmesini desteklemez. Ancak, çalışma zamanı tüm platformlarda başvuruya göre açık yapıların geçirilmesini destekler.
Boole alanı sıralamasını özelleştirme
Yerel kodun birçok farklı Boole gösterimi vardır. Yalnızca Windows'ta Boole değerlerini temsil etmenin üç yolu vardır. Çalışma zamanı yapınızın yerel tanımını bilmiyor, bu nedenle en iyisi Boole değerlerinizi nasıl sıralayabileceğinizi tahmin etmektir. .NET çalışma zamanı, Boole alanınızı hazırlamayı göstermek için bir yol sağlar. Aşağıdaki örneklerde .NET'in bool
farklı yerel Boole türlerine nasıl sıralandığı gösterilmektedir.
Boole değerleri, aşağıdaki örnekte gösterildiği gibi varsayılan olarak yerel 4 baytlık Win32 BOOL
değeri olarak sıralı hale getirmektir:
public struct WinBool
{
public bool b;
}
struct WinBool
{
public BOOL b;
};
Açık olmak istiyorsanız, yukarıdakiyle UnmanagedType.Bool aynı davranışı elde etmek için değerini kullanabilirsiniz:
public struct WinBool
{
[MarshalAs(UnmanagedType.Bool)]
public bool b;
}
struct WinBool
{
public BOOL b;
};
UnmanagedType.U1
Aşağıdaki veya UnmanagedType.I1
değerlerini kullanarak çalışma zamanına alanı 1 baytlık yerel bool
bir tür olarak hazırlamasını b
söyleyebilirsiniz.
public struct CBool
{
[MarshalAs(UnmanagedType.U1)]
public bool b;
}
struct CBool
{
public bool b;
};
Windows'da, çalışma zamanına UnmanagedType.VariantBool Boole değerinizi 2 baytlık VARIANT_BOOL
bir değere hazırlamasını bildirmek için değerini kullanabilirsiniz:
public struct VariantBool
{
[MarshalAs(UnmanagedType.VariantBool)]
public bool b;
}
struct VariantBool
{
public VARIANT_BOOL b;
};
Not
VARIANT_BOOL
ve içindeki bool türlerinin çoğundan VARIANT_TRUE = -1
VARIANT_FALSE = 0
farklıdır. Buna ek olarak, eşit VARIANT_TRUE
olmayan tüm değerler false olarak kabul edilir.
Dizi alanı sıralamasını özelleştirme
.NET ayrıca dizi sıralamasını özelleştirmek için birkaç yol içerir.
Varsayılan olarak, .NET dizileri öğelerin bitişik bir listesinin işaretçisi olarak sıralar:
public struct DefaultArray
{
public int[] values;
}
struct DefaultArray
{
int32_t* values;
};
COM API'leriyle birlikte kullanıyorsanız dizileri nesne olarak SAFEARRAY*
sıralamanız gerekebilir. ve UnmanagedType.SafeArray değerini kullanarak System.Runtime.InteropServices.MarshalAsAttribute çalışma zamanına bir diziyi olarak SAFEARRAY*
hazırlamasını bildirebilirsiniz:
public struct SafeArrayExample
{
[MarshalAs(UnmanagedType.SafeArray)]
public int[] values;
}
struct SafeArrayExample
{
SAFEARRAY* values;
};
içinde SAFEARRAY
ne tür bir öğe olduğunu özelleştirmeniz gerekiyorsa ve MarshalAsAttribute.SafeArrayUserDefinedSubType alanlarını kullanarak MarshalAsAttribute.SafeArraySubType öğesinin tam öğe türünü SAFEARRAY
özelleştirebilirsiniz.
Diziyi yerinde hazırlamanız gerekiyorsa, değerini kullanarak UnmanagedType.ByValArray marshaller'a diziyi yerinde hazırlamasını söyleyebilirsiniz. Bu sıralamayı kullanırken, çalışma zamanının MarshalAsAttribute.SizeConst yapı için doğru alan ayırabilmesi için dizideki öğe sayısı için alana bir değer de sağlamanız gerekir.
public struct InPlaceArray
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] values;
}
struct InPlaceArray
{
int values[4];
};
Not
.NET, değişken uzunlukta bir dizi alanının C99 Esnek Dizi Üyesi olarak sıralanmasını desteklemez.
Dize alanı sıralamasını özelleştirme
.NET ayrıca dize alanlarını sıralamak için çok çeşitli özelleştirmeler sağlar.
Varsayılan olarak, .NET bir dizeyi null olarak sonlandırılan bir dizeye işaretçi olarak sıralar. Kodlama, içindeki alanının System.Runtime.InteropServices.StructLayoutAttributedeğerine StructLayoutAttribute.CharSet bağlıdır. Öznitelik belirtilmezse, kodlama varsayılan olarak ANSI kodlaması olur.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DefaultString
{
public string str;
}
struct DefaultString
{
char* str;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DefaultString
{
public string str;
}
struct DefaultString
{
char16_t* str; // Could also be wchar_t* on Windows.
};
Farklı alanlar için farklı kodlamalar kullanmanız gerekiyorsa veya yapı tanımınızda daha açık olmak istiyorsanız veya değerlerini bir System.Runtime.InteropServices.MarshalAsAttribute öznitelikte kullanabilirsiniz.UnmanagedType.LPStrUnmanagedType.LPWStr
public struct AnsiString
{
[MarshalAs(UnmanagedType.LPStr)]
public string str;
}
struct AnsiString
{
char* str;
};
public struct UnicodeString
{
[MarshalAs(UnmanagedType.LPWStr)]
public string str;
}
struct UnicodeString
{
char16_t* str; // Could also be wchar_t* on Windows.
};
DIZElerinizi UTF-8 kodlamasını kullanarak sıralamak istiyorsanız, içindeki MarshalAsAttributedeğerini kullanabilirsinizUnmanagedType.LPUTF8Str.
public struct UTF8String
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string str;
}
struct UTF8String
{
char* str;
};
Not
Kullanmak UnmanagedType.LPUTF8Str için .NET Framework 4.7 (veya sonraki sürümler) veya .NET Core 1.1 (veya sonraki sürümler) gerekir. .NET Standard 2.0'da kullanılamaz.
COM API'leriyle çalışıyorsanız, dizeyi olarak BSTR
hazırlamanız gerekebilir. UnmanagedType.BStr değerini kullanarak bir dizeyi olarak BSTR
sıralayabilirsiniz.
public struct BString
{
[MarshalAs(UnmanagedType.BStr)]
public string str;
}
struct BString
{
BSTR str;
};
WinRT tabanlı API kullanırken, dizeyi olarak HSTRING
hazırlamanız gerekebilir. UnmanagedType.HString değerini kullanarak bir dizeyi olarak HSTRING
sıralayabilirsiniz. HSTRING
marshalling yalnızca yerleşik WinRT desteğine sahip çalışma zamanlarında desteklenir. .NET 5'te WinRT desteği kaldırıldı, bu nedenle HSTRING
.NET 5 veya daha yeni sürümlerde marshalling desteklenmez.
public struct HString
{
[MarshalAs(UnmanagedType.HString)]
public string str;
}
struct BString
{
HSTRING str;
};
API'niz dizeyi yapıda yerinde geçirmenizi gerektiriyorsa değerini kullanabilirsiniz UnmanagedType.ByValTStr . tarafından sıralanmış ByValTStr
bir dize için kodlamanın özniteliğinden CharSet
belirlendiğini unutmayın. Ayrıca, alan tarafından bir dize uzunluğu geçirilmesini MarshalAsAttribute.SizeConst gerektirir.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DefaultString
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public string str;
}
struct DefaultString
{
char str[4];
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DefaultString
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public string str;
}
struct DefaultString
{
char16_t str[4]; // Could also be wchar_t[4] on Windows.
};
Ondalık alan sıralamasını özelleştirme
Windows üzerinde çalışıyorsanız, yerel CY
veya CURRENCY
yapıyı kullanan bazı API'lerle karşılaşabilirsiniz. Varsayılan olarak, .NET decimal
türü yerel DECIMAL
yapıya göre sıralar. Ancak, bir değeri yerel bir değere dönüştürmesi decimal
için marshaller'a yönerge vermek için CY
değeri ile kullanabilirsiniz MarshalAsAttributeUnmanagedType.Currency.
public struct Currency
{
[MarshalAs(UnmanagedType.Currency)]
public decimal dec;
}
struct Currency
{
CY dec;
};
Birleşimler
Birleşim, aynı belleğin üzerinde farklı veri türleri içerebilen bir veri türüdür. Bu, C dilindeki yaygın bir veri biçimidir. Birleşim kullanılarak .NET'te LayoutKind.Explicit
ifade edilebilir. .NET'te birleşim tanımlarken yapıların kullanılması önerilir. Sınıfların kullanılması düzen sorunlarına neden olabilir ve öngörülemeyen davranışlara neden olabilir.
struct device1_config
{
void* a;
void* b;
void* c;
};
struct device2_config
{
int32_t a;
int32_t b;
};
struct config
{
int32_t type;
union
{
device1_config dev1;
device2_config dev2;
};
};
public unsafe struct Device1Config
{
void* a;
void* b;
void* c;
}
public struct Device2Config
{
int a;
int b;
}
public struct Config
{
public int Type;
public _Union Anonymous;
[StructLayout(LayoutKind.Explicit)]
public struct _Union
{
[FieldOffset(0)]
public Device1Config Dev1;
[FieldOffset(0)]
public Device2Config Dev2;
}
}
Mareşal System.Object
Windows'da, türü belirtilen alanları yerel koda göre sıralayabilirsiniz object
. Bu alanları üç türden birine göre sıralayabilirsiniz:
Varsayılan olarak, object
-typed alanı nesneyi sarmalayan bir IUnknown*
alana göre hazırlanır.
public struct ObjectDefault
{
public object obj;
}
struct ObjectDefault
{
IUnknown* obj;
};
Bir nesne alanını öğesine sıralamak IDispatch*
istiyorsanız, değeriyle birlikte UnmanagedType.IDispatch bir MarshalAsAttribute ekleyin.
public struct ObjectDispatch
{
[MarshalAs(UnmanagedType.IDispatch)]
public object obj;
}
struct ObjectDispatch
{
IDispatch* obj;
};
Bunu olarak VARIANT
sıralamak istiyorsanız, değeriyle bir MarshalAsAttributeUnmanagedType.Struct ekleyin.
public struct ObjectVariant
{
[MarshalAs(UnmanagedType.Struct)]
public object obj;
}
struct ObjectVariant
{
VARIANT obj;
};
Aşağıdaki tabloda, alanın farklı çalışma zamanı türlerinin obj
içinde VARIANT
depolanan çeşitli türlerle nasıl eşlediği açıklanmaktadır:
.NET Türü | VARIANT Türü |
---|---|
byte |
VT_UI1 |
sbyte |
VT_I1 |
short |
VT_I2 |
ushort |
VT_UI2 |
int |
VT_I4 |
uint |
VT_UI4 |
long |
VT_I8 |
ulong |
VT_UI8 |
float |
VT_R4 |
double |
VT_R8 |
char |
VT_UI2 |
string |
VT_BSTR |
System.Runtime.InteropServices.BStrWrapper |
VT_BSTR |
object |
VT_DISPATCH |
System.Runtime.InteropServices.UnknownWrapper |
VT_UNKNOWN |
System.Runtime.InteropServices.DispatchWrapper |
VT_DISPATCH |
System.Reflection.Missing |
VT_ERROR |
(object)null |
VT_EMPTY |
bool |
VT_BOOL |
System.DateTime |
VT_DATE |
decimal |
VT_DECIMAL |
System.Runtime.InteropServices.CurrencyWrapper |
VT_CURRENCY |
System.DBNull |
VT_NULL |
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin