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

时间:2021-07-24 21:04:51

I am getting the above error and unable to resolve it. I googled a bit but can't get rid of it.

我收到上述错误,无法解决。我google了一下,但无法摆脱它。

Scenario:

场景:

I have class BudgetAllocate whose property is budget which is of double type.

我有类BudgetAllocate,其属性是预算,是双重类型。

In my dataAccessLayer,

在我的dataAccessLayer中,

In one of my classes I am trying to do this:

在我的一个课程中,我试图这样做:

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

Which is throwing this error:

这引发了这个错误:

Property or indexer may not be passed as an out or ref parameter at compile time.

在编译时,属性或索引器不能作为out或ref参数传递。

I even tried this:

我甚至试过这个:

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

Everything else is working fine and references between layers are present.

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

6 个解决方案

#1


20  

you cannot use

你不能用

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

replace bd.Budget with some variable.

用某个变量替换bd.Budget。

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

#2


89  

Others have given you the solution, but as to why this is necessary: a property is just syntactic sugar for a method.

其他人给了你解决方案,但至于为什么这是必要的:属性只是方法的语法糖。

For example, when you declare a property called Name with a getter and setter, under the hood the compiler actually generates methods called get_Name() and set_Name(value). Then, when you read from and write to this property, the compiler translates these operations into calls to those generated methods.

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

When you consider this, it becomes obvious why you can't pass a property as an output parameter - you would actually be passing a reference to a method, rather than a reference to an object a variable, which is what an output parameter expects.

当您考虑到这一点时,很明显为什么您不能将属性作为输出参数传递 - 您实际上将传递对方法的引用,而不是对变量的对象的引用,这是输出参数所期望的。

A similar case exists for indexers.

索引器也存在类似的情况。

#3


45  

This is a case of a leaky abstraction. A property is actually a method, the get and set accessors for an indexer get compiled to get_Index() and set_Index methods. The compiler does a terrific job hiding that fact, it automatically translates an assignment to a property to the corresponding set_Xxx() method for example.

这是一个漏洞抽象的案例。属性实际上是一个方法,索引器的get和set访问器被编译为get_Index()和set_Index方法。编译器做了一个很好的工作,隐藏了这个事实,它自动将一个属性的赋值转换为相应的set_Xxx()方法。

But this goes belly up when you pass a method parameter by reference. That requires the JIT compiler to pass a pointer to the memory location of the passed argument. Problem is, there isn't one, assigning the value of a property requires calling the setter method. The called method cannot tell the difference between a passed variable vs a passed property and can thus not know whether a method call is required.

但是,当您通过引用传递方法参数时,这会变得很糟糕。这需要JIT编译器将指针传递给传递参数的内存位置。问题是,没有一个,分配属性的值需要调用setter方法。被调用的方法无法区分传递的变量与传递的属性之间的区别,因此无法知道是否需要进行方法调用。

Notable is that this actually works in VB.NET. For example:

值得注意的是,这实际上适用于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

The VB.NET compiler solves this by automatically generating this code for the Run method, expressed in C#:

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

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

Which is the workaround you can use as well. Not quite sure why the C# team didn't use the same approach. Possibly because they didn't want to hide the potentially expensive getter and setter calls. Or the completely undiagnosable behavior you'll get when the setter has side-effects that change the property value, they'll disappear after the assignment. Classic difference between C# and VB.NET, C# is "no surprises", VB.NET is "make it work if you can".

您也可以使用哪种解决方法。不太清楚C#团队为什么不使用相同的方法。可能是因为他们不想隐藏潜在的昂贵的getter和setter调用。或者当setter具有改变属性值的副作用时,你将获得完全不可识别的行为,它们将在赋值后消失。 C#和VB.NET之间的经典区别,C#是“没有惊喜”,VB.NET是“让它工作,如果你能”。

#4


7  

Place the out parameter into a local variable and then set the variable into bd.Budget:

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

double tempVar = 0.0;

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

Update: Straight from MSDN:

更新:直接来自MSDN:

Properties are not variables and therefore cannot be passed as out parameters.

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

http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx

http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx

#5


5  

Possibly of interest - you could write your own:

可能有兴趣 - 你可以写自己的:

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

#6


1  

So Budget is a property, correct?

所以预算是财产,对吗?

Rather first set it to a local variable, and then set the property value to that.

而是首先将其设置为局部变量,然后将属性值设置为该值。

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

#1


20  

you cannot use

你不能用

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

replace bd.Budget with some variable.

用某个变量替换bd.Budget。

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

#2


89  

Others have given you the solution, but as to why this is necessary: a property is just syntactic sugar for a method.

其他人给了你解决方案,但至于为什么这是必要的:属性只是方法的语法糖。

For example, when you declare a property called Name with a getter and setter, under the hood the compiler actually generates methods called get_Name() and set_Name(value). Then, when you read from and write to this property, the compiler translates these operations into calls to those generated methods.

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

When you consider this, it becomes obvious why you can't pass a property as an output parameter - you would actually be passing a reference to a method, rather than a reference to an object a variable, which is what an output parameter expects.

当您考虑到这一点时,很明显为什么您不能将属性作为输出参数传递 - 您实际上将传递对方法的引用,而不是对变量的对象的引用,这是输出参数所期望的。

A similar case exists for indexers.

索引器也存在类似的情况。

#3


45  

This is a case of a leaky abstraction. A property is actually a method, the get and set accessors for an indexer get compiled to get_Index() and set_Index methods. The compiler does a terrific job hiding that fact, it automatically translates an assignment to a property to the corresponding set_Xxx() method for example.

这是一个漏洞抽象的案例。属性实际上是一个方法,索引器的get和set访问器被编译为get_Index()和set_Index方法。编译器做了一个很好的工作,隐藏了这个事实,它自动将一个属性的赋值转换为相应的set_Xxx()方法。

But this goes belly up when you pass a method parameter by reference. That requires the JIT compiler to pass a pointer to the memory location of the passed argument. Problem is, there isn't one, assigning the value of a property requires calling the setter method. The called method cannot tell the difference between a passed variable vs a passed property and can thus not know whether a method call is required.

但是,当您通过引用传递方法参数时,这会变得很糟糕。这需要JIT编译器将指针传递给传递参数的内存位置。问题是,没有一个,分配属性的值需要调用setter方法。被调用的方法无法区分传递的变量与传递的属性之间的区别,因此无法知道是否需要进行方法调用。

Notable is that this actually works in VB.NET. For example:

值得注意的是,这实际上适用于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

The VB.NET compiler solves this by automatically generating this code for the Run method, expressed in C#:

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

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

Which is the workaround you can use as well. Not quite sure why the C# team didn't use the same approach. Possibly because they didn't want to hide the potentially expensive getter and setter calls. Or the completely undiagnosable behavior you'll get when the setter has side-effects that change the property value, they'll disappear after the assignment. Classic difference between C# and VB.NET, C# is "no surprises", VB.NET is "make it work if you can".

您也可以使用哪种解决方法。不太清楚C#团队为什么不使用相同的方法。可能是因为他们不想隐藏潜在的昂贵的getter和setter调用。或者当setter具有改变属性值的副作用时,你将获得完全不可识别的行为,它们将在赋值后消失。 C#和VB.NET之间的经典区别,C#是“没有惊喜”,VB.NET是“让它工作,如果你能”。

#4


7  

Place the out parameter into a local variable and then set the variable into bd.Budget:

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

double tempVar = 0.0;

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

Update: Straight from MSDN:

更新:直接来自MSDN:

Properties are not variables and therefore cannot be passed as out parameters.

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

http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx

http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx

#5


5  

Possibly of interest - you could write your own:

可能有兴趣 - 你可以写自己的:

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

#6


1  

So Budget is a property, correct?

所以预算是财产,对吗?

Rather first set it to a local variable, and then set the property value to that.

而是首先将其设置为局部变量,然后将属性值设置为该值。

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