Ben dizeleri bayt olduğu bir sürü kullanan bir Borland C API ile C# çalışıyorum. Bazı C# dizeleri (kısa ömürlü) bayt * olarak geçirme ihtiyacı ile karşı karşıya kaldım.C# sabitlenmiş sabitler var mı?
Bir const nesne öbek üzerinde tahsis olmaz, ancak program bellekte depolanmasını olurdu, ama herhangi belgelerinde bu doğrulayamadığınız ettik benim doğal varsayım olurdu.
Burada sabit bir dizeye bir işaretçi üretmek için ne yaptık bir örnek. Bu testte amaçlandığı gibi çalışıyor, gerçekten güvenli olup olmadığından emin değilim, ya da sadece şansla çalışıyor.
private const string pinnedStringGetWeight = "getWeight";
unsafe public static byte* ExampleReturnWeightPtr(int serial)
{
fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight))
return pGetWeight;
}
Bu const gerçekten sabitlenmiş mi, yoksa taşınması mümkün mü?
@Kragen:
[DllImport("sidekick.dll", CallingConvention = CallingConvention.Winapi)]
public static extern int getValueByFunctionFromObject(int serial, int function, byte* debugCallString);
Bu gerçek fonksiyonudur: Burada
ithalatı. Evet, aslında bir statik işlev işaretçisi gerektirir:
private const int FUNC_GetWeight = 0x004243D0;
private const string pinnedStringGetWeight = "getWeight";
unsafe public static int getWeight(int serial)
{
fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight))
return Core.getValueByFunctionFromObject(serial, FUNC_GetWeight, pGetWeight);
}
ardından ben de çivilenmişti ümit statik yapı kullanılarak, benim API alay ederken kullanılan diğer bir yöntemdir. Bunu basitleştirmek için bir yol bulmayı umuyordum. ASCIIEncoding.ASCII.GetBytes()
yeni bayt dizisi döndürür çünkü farklı şekilde kodlanmış olduğundan (bu sabitin iç diziyi döndüremez
public byte* getObjVarString(int serial, byte* varName)
{
string varname = StringPointerUtils.GetAsciiString(varName);
string value = MockObjVarAttachments.GetString(serial, varname);
if (value == null)
return null;
return bytePtrFactory.MakePointerToTempString(value);
}
static UnsafeBytePointerFactoryStruct bytePtrFactory = new UnsafeBytePointerFactoryStruct();
private unsafe struct UnsafeBytePointerFactoryStruct
{
fixed byte _InvalidScriptClass[255];
fixed byte _ItemNotFound[255];
fixed byte _MiscBuffer[255];
public byte* InvalidScriptClass
{
get
{
fixed (byte* p = _InvalidScriptClass)
{
CopyNullString(p, "Failed to get script class");
return p;
}
}
}
public byte* ItemNotFound
{
get
{
fixed (byte* p = _ItemNotFound)
{
CopyNullString(p, "Item not found");
return p;
}
}
}
public byte* MakePointerToTempString(string text)
{
fixed (byte* p = _ItemNotFound)
{
CopyNullString(p, text);
return p;
}
}
private static void CopyNullString(byte* ptrDest, string text)
{
byte[] textBytes = ASCIIEncoding.ASCII.GetBytes(text);
fixed (byte* p = textBytes)
{
int i = 0;
while (*(p + i) != 0 && i < 254 && i < textBytes.Length)
{
*(ptrDest + i) = *(p + i);
i++;
}
*(ptrDest + i) = 0;
}
}
}
Bu değil Yerel kod için marşal dizeleri yolu - C API'nize (muhtemelen P/Invoke) bir çağrı gönderebilir misiniz? – Justin
Sabit dizelerin etkin bir şekilde "sabitlendiğinden" şüpheleniyorum, çünkü çöp yığınında birikmiş yığınlarda saklandıklarına inanmıyorum. Bunun bir kanıtı, sabit dizelerin, "Ldstr" IL opcode kullanılarak, yöntem gövdesinin bir parçası olarak sağlanan sabit dizgeyle yüklenmesidir. –
Önceki ifademi açıklığa kavuşturmalıyım. "Sabit ifade, çöp toplayıcısının hareketli bir değişkeni yeniden konumlandırmasını engeller. Sabit ifadeye yalnızca güvenli olmayan bir bağlamda izin verilir. Sabit, sabit boyutlu tamponlar oluşturmak için de kullanılabilir." - http://msdn.microsoft.com/en-us/library/f58wzh21(v=VS.100).aspx - RunUO böylece 2010 :-) –