属性或索引器不能作为 out 或 ref 参数传递

我得到上述错误,无法解决它。 我谷歌了一下,但是没办法摆脱它。

场景:

我有类 BudgetAllocate的属性是 budgetdouble类型。

在我的 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);

其他一切都工作正常,层之间的引用也存在。

108978 次浏览

你不能使用

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

用一些变量代替 bd。

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

所以预算案是一个财产,对不对?

首先将它设置为一个局部变量,然后将属性值设置为该局部变量。

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

将 out 参数放入一个局部变量中,然后将该变量设置为 bd.Budget:

double tempVar = 0.0;


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

更新 : 直接来自 MSDN:

属性不是变量 因此不能传递为 out 参数。

其他人已经给出了解决方案,但是至于为什么需要这样做: 属性只是 方法的语法糖。

例如,当使用 getter 和 setter 声明名为 Name的属性时,编译器实际上在底层生成名为 get_Name()set_Name(value)的方法。然后,在读取和写入此属性时,编译器将这些操作转换为对这些生成的方法的调用。

当您考虑这个问题时,很明显就可以看出为什么不能将属性作为输出参数传递-您实际上传递的是对 方法的引用,而不是对 一个物体变量的引用,这正是输出参数所期望的。

索引器也有类似的情况。

这是一起抽象漏洞定律。属性实际上是一个方法,索引器的 走开准备好了访问器被编译为 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

NET 编译器通过自动生成 Run 方法的代码解决了这个问题,代码用 C # 表示:

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

这也是你可以使用的变通方法。不太确定为什么 C # 团队没有使用相同的方法。可能是因为他们不想隐藏潜在的昂贵的 getter 和 setter 调用。或者当 setter 具有改变属性值的副作用时,您将获得完全无法诊断的行为,它们将在赋值后消失。C # 和 VB.NET 的经典区别在于,C # 是“毫无意外”,而 VB.NET 是“如果可以的话,尽量让它工作”。

也许你会感兴趣——你可以自己写:

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

这是一个非常老的职位,但我正在修改接受,因为有一个更方便的方式来做这一点,我不知道。

它被称为内联声明,可能一直都是可用的(比如在使用语句时) ,或者可能已经为这种情况添加了 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;

通常当我尝试这样做是因为我想设置我的属性或保持它的默认值。在 这个答案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 变量。我不是程序员,如果我误解了这个问题,我真的很抱歉。