4

.net構造(接続されたデバイスの内部マップを模倣)が必要であり、Marshall.PtrToStructure()および関連するGChandleのものを使用しているため、trycatchブロックを使用したいと思います。ただし、構造体のフィールド割り当てをtry catchブロック内に配置すると、「制御が送信者に返される前に、field1を完全に割り当てる必要があります」というエラーが発生します。基本的なコードは、trycatchブロックがなくても正常に機能します。try catchブロックを使用しているときにこのエラーを回避する方法はありますか?try catchを使用する必要がありますか?

[StructLayout( LayoutKind.Sequential )]
public struct Effects
{
    public UInt16 field_1;
    public UInt16 field_2;
    ...



    public Effects(byte[] effectsData)
    {
       GCHandle gch;
       try
       {
           gch = GCHandle.Alloc( effectsData, GCHandleType.Pinned );
           IntPtr pEffects = gch.AddrOfPinnedObject( );
           this = (Effects)Marshal.PtrToStructure( pEffects, typeof(Effects ) );
       }
       catch (Exception ex)
       {

       }
       finally
       {
           if (gch.IsAllocated)
               gch.Free( );
       }
    }
}
4

8 に答える 8

13

コンストラクターは、正常に戻った場合、すべてのフィールドが入力されることを保証する必要があります。

コードがの最初の行で例外をスローするとしますtry。次に、例外をキャッチし、それを食べて、フィールドに入力することなく戻ってきます。コンパイラはこれを検出し、プログラムを許可しません。

すべての例外を食べることは、ここで行うのはほぼ間違いなく間違ったことです。未処理で予期しない任意の例外が発生した場合、本当に初期化されていない構造を返したいですか?

それがあなたがしたいことであるならば、あなたは単に言うことができます:

public Effects(byte[] effectsData) : this() {

これにより、ctorブロックが実行される前に、フィールドがデフォルト値に初期化されることが保証されます。

しかし、繰り返しますが、それは本当にあなたがやりたいことですか?このコードは私には非常に危険に見えます。

于 2012-04-19T16:21:46.753 に答える
4

例外が発生した場合、どうしますか?現在のコードでは、tryブロックで例外が発生すると、例外が飲み込まれ(catchブロックが空であるため)、構造が初期化されていません。これはまさにコンパイラが不満を言っていることです。

最後の部分にのみtry-catchブロックが必要な場合は、catchブロックをまったく使用せず、try-finallyだけを使用してください。エラーをキャッチしないことで、ユーザーインターフェイスにエラーが発生するようにします。空のキャッチブロックよりも(ほとんど)常に優れているキャッチブロックはありません。キャッチブロックが空の場合、コードが「機能しない」だけで、何が問題だったのかがわからないため、デバッグが悪夢になります。

したがって、私はあなたのコードを次のように書き直します:

public Effects(byte[] effectsData) 
{ 
     GCHandle gch = GCHandle.Alloc( effectsData, GCHandleType.Pinned ); 
     try 
     { 
         IntPtr pEffects = gch.AddrOfPinnedObject( ); 
         this = (Effects)Marshal.PtrToStructure( pEffects, typeof(Effects ) ); 
     } 
     finally 
     { 
        if (gch.IsAllocated)
            gch.Free( ); 
     } 
} 

(でエラーが発生した場合GCHandle.Alloc、gchは割り当てられないため、try-finallyブロックに含める必要はありません。)

于 2012-04-19T16:20:46.970 に答える
2

これをコンストラクターに追加します

field_1 = 0;
field_2 = 0;
...

構造体はクラスとは異なる動作をします。コンストラクターですべてのフィールドを明示的に割り当てる必要があります。

于 2012-04-19T16:20:12.690 に答える
2

コンストラクターで構造のすべてのプロパティを設定する必要があります。

try / catchを挿入したときに、すべてのコードパスでこれらのプロパティを設定できるわけではありません

次のようなものが必要になる場合があります。

try
{
   // Tries to affect something

   // Then returns
   return;
}
catch (Exception ex)
{
    // Set default values
    this.field1 = ....
}
finally
{
   if (gch.IsAllocated)
       gch.Free( );
}
于 2012-04-19T16:20:38.313 に答える
1

コンストラクターを離れる前に、構造体のメンバーをすべて初期化する必要があります。

例外をキャッチしたときに何かをスローするか、try-catchループに入る前に、データメンバーを適切なものに初期化します。または、catchブロック内の何かに値を初期化することもできます。

于 2012-04-19T16:18:26.627 に答える
1

問題は空のcatchブロックです。例外が発生した場合、構造をどのように初期化する必要がありますか?

本当に例外を無視したい場合はthis、catchブロック内でデフォルト値に初期化する必要があります。すべてのフィールドをゼロに設定するには、

this = new Effects();

または、例外をコンストラクターから伝播させることで問題を回避できます。

于 2012-04-19T16:19:49.320 に答える
1

静的メンバーは、2番目のコンストラクターを提供するよりもはるかに問題が少なく混乱しません。

public static Effects Create(byte[] effectsData)
{
   GCHandle gch;
   try
   {
       gch = GCHandle.Alloc( effectsData, GCHandleType.Pinned );
       IntPtr pEffects = gch.AddrOfPinnedObject( );
       return (Effects)Marshal.PtrToStructure( pEffects, typeof(Effects) );
   }
   finally
   {
       if (gch.IsAllocated)
           gch.Free( );
   }
}

この場合の例外処理は、簡単に理解して維持できます。

于 2012-04-19T16:27:17.417 に答える
0

確かに、バイト配列のレイアウトを知っている必要がありますか?BitConverterクラスを使用してフィールドを初期化します。このようにして、ピン留め、try-finally、およびその他の不要なオーバーヘッドについて心配する必要はありません。

[StructLayout( LayoutKind.Sequential )]
public struct Effects
{
    public UInt16 field_1;
    public UInt16 field_2;

    public static Effects FromBytes(byte[] data)
    {
        var value = new Effects();
        value.field_1 = BitConverter.ToUInt16(data, 0);
        value.field_2 = BitConverter.ToUInt16(data, 2);
        return value;
    }
}

エンディアンと配置の違いに対応するために必要な調整を行います。

于 2012-04-19T17:31:44.490 に答える