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

发布于 2024-10-09 02:12:40 字数 544 浏览 0 评论 0原文

我收到上述错误并且无法解决。 我用谷歌搜索了一下,但无法摆脱它。

场景:

我有类 BudgetAllocate ,其属性为 budget ,属于 double 类型。

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

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

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

Scenario:

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

In my 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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

风吹短裙飘 2024-10-16 02:12:40

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

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

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

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

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.

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.

欢你一世 2024-10-16 02:12:40

这是一个抽象漏洞的例子。属性实际上是一种方法,索引器的 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 调用。或者,当设置器具有更改属性值的副作用时,您将得到完全无法诊断的行为,它们将在赋值后消失。 C# 和 VB.NET 之间的经典区别,C# 是“没有惊喜”,VB.NET 是“如果可以的话,让它工作”。

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.

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.

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

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#:

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".

甲如呢乙后呢 2024-10-16 02:12:40

您不能使用

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

某些变量替换 bd.Budget 。

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

you cannot use

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

replace bd.Budget with some variable.

double k;
double.TryParse(objReader[i].ToString(), out k); 
bd.Budget = k;
久隐师 2024-10-16 02:12:40

可能感兴趣 - 您可以编写自己的:

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

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;
}
怎会甘心 2024-10-16 02:12:40

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

double tempVar = 0.0;

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

更新:直接来自 MSDN:

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

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

double tempVar = 0.0;

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

Update: Straight from MSDN:

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

内心旳酸楚 2024-10-16 02:12:40

这是一篇非常古老的帖子,但我正在修改已接受的帖子,因为有一种我不知道的更方便的方法。

它被称为内联声明,并且可能一直可用(如在 using 语句中),或者在这种情况下可能已使用 C#6.0 或 C#7.0 添加了它,不确定,但无论如何都像魅力一样:

此使用的 Inetad

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

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

This is a very old post, but I'm ammending the accepted, because there is an even more convienient way of doing this which I didn't know.

It's called inline declaration and might have always been available (as in using statements) or it might have been added with C#6.0 or C#7.0 for such cases, not sure, but works like a charm anyway:

Inetad of this

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

use this:

double.TryParse(objReader[i].ToString(), out double temp);
bd.Budget = temp;
誰認得朕 2024-10-16 02:12:40

所以预算是一种财产,对吗?

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

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

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;
嘿嘿嘿 2024-10-16 02:12:40

我遇到了同样的问题(5 分钟前),我使用带有 getter 和 setter 的旧样式属性解决了这个问题,它们使用变量。
我的代码:

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

所以,我只是使用了 bigField 变量。我不是程序员,如果我误解了这个问题,我真的很抱歉。

I had the same problem (5 minutes ago) and I solved it using old style properties with getter and setter, whose use variables.
My code:

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

So, I just used bigField variable. I'm not the programmer, if I misunderstood the question, I'm really sorry.

仅一夜美梦 2024-10-16 02:12:40

通常,当我尝试执行此操作时,这是因为我想设置我的属性或将其保留为默认值。借助这个答案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));

Usually when I'm trying to do this it's because I want to set my property or leave it at the default value. With the help of this answer and dynamic types we can easily create a string extension method to keep it one lined and simple.

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

Use like so;

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

Optional

On a side note, if that's an SQLDataReader you may also make use of GetSafeString extension(s) to avoid null exceptions from the reader.

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

Use like so;

bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double));
bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
风柔一江水 2024-10-16 02:12:40

如果您使用“ref”关键字,请不要使用“properties”,它会在编译时带来很多问题和错误。保持老派,只使用简单明了的字段。所以这就是答案:

class BudgetAllocate
{
 private double budget;
 public double Budget { get => budget; set => budget = value}
}

if you using "ref" keyword please don't use "properties" it brings a lot of problems and errors in compile time. keep it old school and just use plain and simple fields. so this is the answer:

class BudgetAllocate
{
 private double budget;
 public double Budget { get => budget; set => budget = value}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文