如何在C#中通过引用传递属性

时间:2014-09-15 11:25:33

标签: c#

我有一个进程要将其应用于任意对象的多个值类型属性,以便进程以某种方式修改每个属性。将进程应用于传递给它的任何给定属性的方法似乎是要走的路,但因为属性是值类型,所以除非我通过引用传递它,否则它不会被更改,但当然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.

其中anObject.SampleTextn都是字符串。

我不能成为第一个想要做类似事情的人!

我正在使用VS2008(C#3.5)

TIA

2 个答案:

答案 0 :(得分:4)

你做不到。这个概念不存在。您必须将值分配给临时局部变量,对变量使用ref,然后将返回分配给属性:

var tmp = anObject.SampleText1;
AssignStringValueOrLeaveIfNull(value1, ref tmp);
anObject.SampleText1 = tmp;

或使用返回值,这可能更简单......

anObject.SampleText1 = AssignStringValueOrLeaveIfNull(value1, anObject.SampleText1);

ref适用于:

  • 字段
  • 局部变量
  • 数组元素
  • 参数

使用属性,因为属性实际上是方法调用,并且方法调用的结果没有ref来自的合理位置。注意:在IL级别,你可以从方法返回值ref,这理论上可以允许类似于此的东西 - 但它现在不会在C#中暴露(如果有的话) ),它不适用于今天存在的属性。

答案 1 :(得分:0)

您可以编写一个丑陋的extension method,其中包含表达式代表您要设置的属性,并让它有机会检查您的新值是否为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);
            }
        }
    }
}

Source

然后你可以使用它:

anObject.SetPropertyValue(a => a.SampleText1, value1);
anObject.SetPropertyValue(a => a.SampleText2, value2);

这应该允许你避免将对象标记为“脏”,但是相当昂贵(正如Marc在his answer的评论中提到的那样)。