web-dev-qa-db-ja.com

プロパティまたはインデクサーをoutまたはrefパラメーターとして渡すことはできません

上記のエラーが表示され、解決できません。私は少しグーグルで調べましたが、それを取り除くことはできません。

シナリオ:

プロパティが二重タイプの予算であるクラスBudgetAllocateがあります。

私のdataAccessLayerでは、

私のクラスの1つでこれをやろうとしています:

double.TryParse(objReader[i].ToString(), out bd.Budget);

これはこのエラーを投げています:

プロパティまたはインデクサーは、コンパイル時にoutまたはrefパラメーターとして渡されない場合があります。

私もこれを試しました:

double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);

それ以外はすべて正常に機能しており、レイヤー間の参照が存在します。

71
Pratik

使用できません

double.TryParse(objReader[i].ToString(), out bd.Budget); 

bd.Budgetを何らかの変数に置き換えます。

double k;
double.TryParse(objReader[i].ToString(), out k); 
29
dhinesh

他の人があなたに解決策を与えましたが、なぜこれが必要なのか:プロパティはmethodの単なる構文糖です。

たとえば、Nameというプロパティをゲッターとセッターで宣言すると、実際にはコンパイラーはget_Name()およびset_Name(value)というメソッドを生成します。次に、このプロパティを読み書きすると、コンパイラはこれらの操作を生成されたメソッドの呼び出しに変換します。

これを検討すると、プロパティを出力パラメーターとして渡すことができない理由が明らかになります。実際には、参照ではなくmethodへの参照を渡すことになります。 オブジェクト 変数。これは出力パラメーターが期待するものです。

インデクサーにも同様のケースがあります。

121

これは、漏れやすい抽象化の場合です。プロパティは実際にはメソッドであり、インデクサーのgetおよびsetアクセサーはget_Index()およびset_Indexメソッドにコンパイルされます。コンパイラーはその事実を隠す素晴らしい仕事をします。例えば、プロパティへの割り当てを対応するset_Xxx()メソッドに自動的に変換します。

しかし、参照によってメソッドパラメーターを渡すと、これはおしまいになります。それには、JITコンパイラーが、渡された引数のメモリー位置へのポインターを渡す必要があります。問題は、1つではなく、プロパティの値を割り当てるには、setterメソッドを呼び出す必要があるということです。呼び出されたメソッドは、渡された変数と渡されたプロパティの違いを知ることができないため、メソッド呼び出しが必要かどうかを知ることができません。

注目すべきは、これが実際にVB.NETで機能することです。例えば:

Class Example
    Public Property Prop As Integer

    Public Sub Test(ByRef arg As Integer)
        arg = 42
    End Sub

    Public Sub Run()
        Test(Prop)   '' No problem
    End Sub
End Class

VB.NETコンパイラは、C#で表現されたRunメソッド用にこのコードを自動的に生成することにより、これを解決します。

int temp = Prop;
Test(ref temp);
Prop = temp;

どの回避策も使用できます。 C#チームが同じアプローチを使用しなかった理由はよくわかりません。おそらく、彼らは潜在的に高価なゲッターとセッターの呼び出しを隠したくなかったからでしょう。または、セッターにプロパティ値を変更する副作用がある場合に発生する完全に診断不可能な動作は、割り当て後に消えます。 C#とVB.NETの古典的な違いは、C#は「驚き」ではなく、VB.NETは「できる限り機能させる」ことです。

53
Hans Passant

出力パラメーターをローカル変数に配置してから、変数をbd.Budgetに設定します。

double tempVar = 0.0;

if (double.TryParse(objReader[i].ToString(), out tempVar))
{
    bd.Budget = tempVar;
}

更新:MSDNから直接:

プロパティは変数ではないため、出力パラメーターとして渡すことはできません。

8

おそらく興味がある-あなたはあなた自身を書くことができます:

    //double.TryParse(, out bd.Budget);
    bool result = TryParse(s, value => bd.Budget = value);
}

public bool TryParse(string s, Action<double> setValue)
{
    double value;
    var result =  double.TryParse(s, out value);
    if (result) setValue(value);
    return result;
}
7

これは非常に古い記事ですが、これを行うもっと便利な方法がありますが、私は知りませんでしたので、私は受け入れられたものを修正しています。

これはインライン宣言と呼ばれ、(ステートメントの使用のように)常に利用可能であるか、そのような場合にC#6.0またはC#7.0で追加された可能性がありますが、確かではありませんが、とにかく魅力のように動作します:

これのイネータ

double temp;
double.TryParse(objReader[i].ToString(), out temp);
bd.Budget = temp;

これを使って:

double.TryParse(objReader[i].ToString(), out double temp);
bd.Budget = temp;
3
DanDan

予算は財産ですよね?

むしろ、最初にローカル変数に設定してから、プロパティ値をそれに設定します。

double t = 0;
double.TryParse(objReader[i].ToString(), out t); 
bd.Budget = t;
1
Adriaan Stander