簡體   English   中英

屬性或索引器不能作為 out 或 ref 參數傳遞

[英]A property or indexer may not be passed as an out or ref parameter

我收到上述錯誤,無法解決。 我用谷歌搜索了一下,但無法擺脫它。

設想:

我有 class BudgetAllocate ,其屬性是double類型的budget

在我的dataAccessLayer中,

在我的一堂課中,我正在嘗試這樣做:

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

這是拋出此錯誤:

屬性或索引器不能在編譯時作為 out 或 ref 參數傳遞。

我什至試過這個:

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

其他一切工作正常,並且存在層之間的引用。

其他人已經為您提供了解決方案,但至於為什么這是必要的:屬性只是方法的語法糖。

例如,當您使用 getter 和 setter 聲明名為Name的屬性時,編譯器實際上會生成名為get_Name()set_Name(value) 然后,當您讀取和寫入此屬性時,編譯器會將這些操作轉換為對這些生成方法的調用。

當您考慮到這一點時,很明顯為什么您不能將屬性作為輸出參數傳遞 - 您實際上將傳遞對方法的引用,而不是對對象變量的引用,這是輸出參數所期望的。

索引器也存在類似的情況。

這是一個泄漏抽象的情況。 屬性實際上是一個方法,索引器的getset訪問器被編譯為 get_Index() 和 set_Index 方法。 編譯器在隱藏這一事實方面做得非常出色,例如,它會自動將賦值給屬性轉換為相應的 set_Xxx() 方法。

但是當您通過引用傳遞方法參數時,這會變得很糟糕。 這需要 JIT 編譯器傳遞一個指向所傳遞參數的內存位置的指針。 問題是,沒有一個,分配一個屬性的值需要調用 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 編譯器通過為 Run 方法自動生成以下代碼來解決這個問題,用 C# 表示:

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

您也可以使用哪種解決方法。 不太確定為什么 C# 團隊不使用相同的方法。 可能是因為他們不想隱藏潛在的昂貴的 getter 和 setter 調用。 或者當 setter 具有更改屬性值的副作用時,您將獲得完全無法診斷的行為,它們將在賦值后消失。 C# 和 VB.NET 的經典區別,C# 是“沒有驚喜”,VB.NET 是“如果可以的話,讓它工作”。

你不能使用

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

用一些變量替換 bd.Budget。

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

將 out 參數放入局部變量,然后將變量設置為bd.Budget

double tempVar = 0.0;

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

更新:直接來自 MSDN:

屬性不是變量,因此不能作為輸出參數傳遞。

可能感興趣 - 您可以編寫自己的:

    //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;
}

這是一個非常古老的帖子,但我正在修改已接受的帖子,因為有一種我不知道的更方便的方法。

它被稱為內聯聲明並且可能一直可用(如在 using 語句中),或者它可能已在 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;

所以預算是一種財產,對嗎?

而是首先將其設置為局部變量,然后將屬性值設置為該變量。

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

通常,當我嘗試這樣做時,是因為我想設置我的屬性或將其保留為默認值。 這個答案dynamic類型的幫助下,我們可以輕松創建一個字符串擴展方法來保持它的內襯和簡單。

public static dynamic ParseAny(this string text, Type type)
{
     var converter = TypeDescriptor.GetConverter(type);
     if (converter != null && converter.IsValid(text))
          return converter.ConvertFromString(text);
     else
          return Activator.CreateInstance(type);
}

像這樣使用;

bd.Budget = objReader[i].ToString().ParseAny(typeof(double));

// Examples
int intTest = "1234".ParseAny(typeof(int)); // Result: 1234
double doubleTest = "12.34".ParseAny(typeof(double)); // Result: 12.34
decimal pass = "12.34".ParseAny(typeof(decimal)); // Result: 12.34
decimal fail = "abc".ParseAny(typeof(decimal)); // Result: 0
string nullStr = null;
decimal failedNull = nullStr.ParseAny(typeof(decimal)); // Result: 0

可選

附帶說明一下,如果這是一個SQLDataReader您還可以使用GetSafeString擴展來避免來自讀取器的空異常。

public static string GetSafeString(this SqlDataReader reader, int colIndex)
{
     if (!reader.IsDBNull(colIndex))
          return reader.GetString(colIndex);
     return string.Empty;
}

public static string GetSafeString(this SqlDataReader reader, string colName)
{
     int colIndex = reader.GetOrdinal(colName);
     if (!reader.IsDBNull(colIndex))
          return reader.GetString(colIndex);
     return string.Empty;
}

像這樣使用;

bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double));
bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));

我遇到了同樣的問題(5 分鍾前),我使用帶有 getter 和 setter 的舊樣式屬性解決了它,它們的使用變量。 我的代碼:

public List<int> bigField = new List<int>();
public List<int> BigField { get { return bigField; } set { bigField = value; } }

所以,我只是使用了 bigField 變量。 我不是程序員,如果我誤解了這個問題,我真的很抱歉。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM