我收到上述错误但无法解决。 我google了一下,但无法摆脱它。
情景:
我有类BudgetAllocate,其属性是预算,是双重类型。
在我的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);
其他一切工作正常,层之间的引用也存在。
答案 0 :(得分:113)
其他人已经为您提供了解决方案,但至于为什么这是必要的:属性只是方法的语法糖。
例如,当您使用getter和setter声明名为Name
的属性时,编译器实际上会生成名为get_Name()
和set_Name(value)
的方法。然后,当您读取和写入此属性时,编译器会将这些操作转换为对这些生成的方法的调用。
当你考虑这个时,很明显为什么你不能将属性作为输出参数传递 - 你实际上是要传递对方法的引用,而不是对的引用一个对象一个变量,这是输出参数所期望的。
索引器存在类似的情况。
答案 1 :(得分:49)
这是一个漏洞抽象的案例。属性实际上是一种方法,索引器的 get 和 set 访问器被编译为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“让你的工作变得有用”。
答案 2 :(得分:26)
你不能使用
double.TryParse(objReader[i].ToString(), out bd.Budget);
用某个变量替换bd.Budget。
double k;
double.TryParse(objReader[i].ToString(), out k);
答案 3 :(得分:8)
将out参数放入局部变量,然后将变量设置为bd.Budget
:
double tempVar = 0.0;
if (double.TryParse(objReader[i].ToString(), out tempVar))
{
bd.Budget = tempVar;
}
更新:直接来自MSDN:
属性不是变量和 因此不能被传递出去 参数。
http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx
答案 4 :(得分:6)
可能有兴趣 - 你可以写自己的:
//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;
}
答案 5 :(得分:3)
这是一篇非常古老的文章,但是我要修改被接受的内容,因为有一种我不知道的更简便的方法。
它称为内联声明,可能一直可用(如使用语句),或者在某些情况下可能已经与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;
答案 6 :(得分:1)
所以预算是财产,对吗?
首先将其设置为局部变量,然后将属性值设置为该值。
double t = 0;
double.TryParse(objReader[i].ToString(), out t);
bd.Budget = t;
答案 7 :(得分:0)
通常,当我尝试执行此操作时,这是因为我想设置属性或将其保留为默认值。在this answer和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));