如何在C#中通过引用传递属性
本文关键字:引用 属性 | 更新日期: 2023-09-27 18:21:51
我有一个进程,我想将它应用于任意对象的多个值类型属性,这样每个属性都会被进程以某种方式修改。将过程应用于传递给它的任何给定属性的方法似乎是可行的,但由于属性是一种值类型,除非我通过引用传递它,否则它不会被更改,但当然,C#编译器会阻止通过引用传递属性。
在编译器不反对或不必为每个属性重复相同条件代码的情况下,我如何实现以下目标?
static internal void AssignStringValueOrLeaveIfNull(string newValue, string sampleValue)
{
if (!string.IsNullOrEmpty(newValue))
sampleValue = newValue;
}
...
AssignStringValueOrLeaveIfNull(value1, anObject.SampleText1);
AssignStringValueOrLeaveIfNull(value2, anObject.SampleText2);
AssignStringValueOrLeaveIfNull(value3, anObject.SampleText3);
AssignStringValueOrLeaveIfNull(value4, anObject.SampleText4);
AssignStringValueOrLeaveIfNull(value5, anObject.SampleText5);
...etc, 30 times.
其中,Object.SampleTextn都是字符串。
我不可能是第一个想做类似事情的人!
我使用的是VS2008(C#3.5)
TIA
您不能。这一概念并不存在。您必须将值分配给一个临时本地变量,在变量上使用ref
,然后将其分配回属性:
var tmp = anObject.SampleText1;
AssignStringValueOrLeaveIfNull(value1, ref tmp);
anObject.SampleText1 = tmp;
或者使用返回值,这可能更简单。。。
anObject.SampleText1 = AssignStringValueOrLeaveIfNull(value1, anObject.SampleText1);
ref
与一起工作
- 字段
- 局部变量
- 数组元素
- 参数
它不能处理属性,因为属性实际上是方法调用,并且方法调用的结果对于ref
没有一个合理的位置。注意:在IL级别,可以从方法中获得ref
返回值,这在理论上允许类似的操作,但它目前没有在C#中公开(如果有的话),而且它不能与当前存在的属性一起使用。
您可以编写一个丑陋的扩展方法,该方法使用一个代表您要设置的属性的表达式,并在分配值之前让它有机会检查您的新值是null
还是空的(或与目标不同)。
public static void SetPropertyValue<T>(this T target, Expression<Func<T, string>> memberLamda, string value)
{
// Check if "new value" is null or empty and bail if so
if (string.IsNullOrEmpty(value))
return;
var memberSelectorExpression = memberLamda.Body as MemberExpression;
if (memberSelectorExpression != null)
{
var property = memberSelectorExpression.Member as PropertyInfo;
if (property != null)
{
// Get the existing value and compare against the new value
// Only set the property if it's different from the existing value
if ((string)property.GetValue(target, null) != value)
{
property.SetValue(target, value, null);
}
}
}
}
来源
然后你可以像这样使用它:
anObject.SetPropertyValue(a => a.SampleText1, value1);
anObject.SetPropertyValue(a => a.SampleText2, value2);
这应该可以避免将对象标记为"脏",但成本相当高(正如Marc在回答中提到的那样)。