2012-11-08 6 views
8

へのポインタを宣言することはできません。は、のアドレスを取るのサイズを取得、または私が研究の公平なビットを行ってきたが、私はまだ、このエラーを取得しています理由として、今立ち往生していますマネージ型

struct Account 
{ 
    //private attributes 
    private double mBalance; 
    private int mAccountNumber; 
    private string mName; 
    private string mDateCreated; 
} 

と次のことを実行しようとしています:

class BankManager 
{ 
    //private attributes 
    private unsafe Account *mAccounts; 
    private unsafe bool *mAccountsAvailable; 
    private int mNumberAccounts; 
} 

でも構造体への私のクラスのアカウントを回した後、クラスの属性のために「安全でない」を使用して、私は次の属性を持つ構造体を持っていますBankManager、およびコンパイラ、それは危険なコードを使用することができます伝える(プロパティで - >ビルド)が、私はまだ理由として

*mAccounts 

で任意のアイデアを、このエラーを取得していますか?私は、構造体で使用しているすべての型がC#のポインタを持つことは合法だと確信しています。前もって感謝します!

+1

なぜポインタを使用しますか? 'BankManager'には' Account'の 'Collection'があります。 – Xint0

+0

これは役立ちます:http://stackoverflow.com/questions/2559384/cannot-take-the-address-of-get-the-size-of-or-declare-a-pointer-to-managed-t – sellmeadog

答えて

20

アカウントクラスの文字列でこの問題が発生します。理由を理解するには、ガベージコレクタの仕組みを理解する必要があります。オブジェクトへの参照を追跡してゴミを発見します。 mNameおよびmDateCreatedはそのような参照です。 mBalanceとmAccountNumberはではなく、であり、これらのフィールドは値タイプです。そして最も重要なのはBankManager.mAccountsフィールドではなく、ポインタです。

したがって、コンパイラは、ガベージコレクタがになることを決して知らずに、が文字列参照を参照できるようにすることができます。そうするための唯一の方法は、mAccountフィールドとそれを参照するのではないためです。このため

唯一の治療法は、値の型に厳密に自分自身を制限することです。文字列のためにこれを行う唯一の方法は、の非管理型メモリにMarshal.StringToCoTaskMemUni()などのメモリを割り当てて、IntPtrをフィールドに格納することです。それは今ガベージコレクターからの手の届かないところにあり、それによって移動することはできません。あなたは今もその文字列を解放する負担があります。

明らかにそれが漏れ、Cプログラムではとても一般的です、問題の種類を引き起こすために実用的となりやすいではありません。なぜこれを追求しているのか分かりませんが、オブジェクトへの参照はすでに単純なポインタであるため、ポインタを使って何も得られていないことに注意してください。

+0

詳細情報をありがとう! – SantasNotReal

0

stringは、ポインタ参照を持つことができないマネージ型であるため、あなたは、ポインタを持つことができる種類を含む構造体について間違っています。

1

使用private unsafe fixed char mName[126];
文字列は管理されたタイプであり、固定されていない配列もあります。

+0

文字列は管理されていますが、文字は許可されています。だから私は上記を行うとき、私は得る: 公開char名 { get {return mName; } セット{mName =値; } } 「固定されていない式に含まれる固定サイズのバッファは使用できません。固定ステートメントを使用してください。」 – SantasNotReal

3

文字列は、.NETの参照型であり、構造体のポインタのための非blittable型です。あなたがやりたいことのための値の種類のリストについては、Blittable and Non-Blittable Typesを参照してください。

あなたは特別なビジネス要件がない限り、あなたは保守性と一般的な健全性のために管理するメモリに固執すべきです。

+0

この回答は、より大きな設計上の問題を記述しているので、受け入れられた答えよりも私にとって有益でした。私の特に問題はblittableではなく、OPと同じエラーが発生するint []配列プロパティを含む構造体に関連していました。 –

-1

管理されたデータは一定の場所に留まらないため、コピーコレクタは物事を移動できます。これは、マネージドボックス化された値の型にも同じです。管理されたボックス化されていない値の型は、スタックまたは他のオブジェクトの中にしか存在できません。スタック内にある場合、それらは固定された位置しか持たない。

有効な引き続き使用できる固定位置を持つヒープ割り当て構造体を作成するには、アンマネージドメモリに割り当てる必要があります。 しかし、ガベージコレクタはこれらのポインタについて知りませんので、管理されていないメモリに管理ポインタを置くことはできません(別名、文字列は使用できません)。圧縮されている間に管理されたオブジェクトを動かすときに、我々はアンマネージメモリ内の構造体を割り当てられている。ここ

[StructLayout(LayoutKind.Sequential, Pack=1)] 
public unsafe struct Account { 
    public int a; 
    public char* mName; 
} 
public class BankManager { 
    private unsafe Account* mAccounts; 
    public unsafe int GetA() { 
     return mAccounts->a; 
    } 
    public unsafe BankManager() { 
     mAccounts = (Account*)Marshal.AllocHGlobal(sizeof(Account)); 
    } 
    unsafe ~BankManager() { 
     if (mAccounts != null) { 
      Marshal.FreeHGlobal((IntPtr)mAccounts); 
      mAccounts = null; 
     } 
    } 
} 

例えば、これは行うには(必ずしも良好ではないが)有効なものです。これにより、変更または移動しないことがわかっているポインタを保持することができます。私たちは手動で構造体を解放する必要があります。管理されていないchar *(cスタイルの文字列)の方法であるため、同じ手動alloc/freeとmarshallingをmAccounts-> mNameに行う必要があります。

構造体には、このコードの動作をC準拠に近づけるためにパックされたシーケンシャルレイアウトが用意されています。これは通常、特定の構造体が必要なネイティブC DllImportエントリポイントとの相互運用レイアウト。

関連する問題