【问题标题】:Simplest C# code to poll a property?轮询属性的最简单的 C# 代码?
【发布时间】:2011-09-30 12:13:32
【问题描述】:

我想知道用于轮询属性值的最简单代码,以执行其 getter 中的代码。
目前我正在使用:instance.property.ToString();,但我宁愿有一些没有可能的副作用或不必要的开销的东西。

【问题讨论】:

  • Instance.Property 肯定会执行 getter 的代码。请详细说明您的问题,我认为我不明白。
  • “可能的副作用”是什么意思?如果您正在调用 getter,则执行 get 代码可能(取决于它的编写方式)导致副作用,无论您如何调用它。
  • @Protector - 你想达到什么目的?也许您要执行的代码不应该进入属性 getter。
  • @mcabral Instance.Property 确实会轮询它,但这不是一个完整的陈述。我不能只是在结尾处打一个分号并希望编译器不会注意到。
  • 或者,您可以调用您的扩展方法Touch,如instance.SomeProperty.Touch(); 那样至少您的代码提供了一些关于正在发生的事情的线索。

标签: c# properties


【解决方案1】:

(我假设您试图避免因简单地将值分配给未使用的变量而得到的警告。)

你可以写一个无操作扩展方法:

public static void NoOp<T>(this T value)
{
    // Do nothing.
}

然后调用:

instance.SomeProperty.NoOp();

这不会将值装箱或触摸它 - 只需调用 getter。与ToString 相比,它的另一个优点是,如果值是空引用,它就不会爆炸。

要求每个值类型对方法进行一次 JIT 编译,但这是一个非常小的成本...

【讨论】:

  • 不会将它分配给未使用的变量也会浪费内存吗? (而且我确实不想要那个警告。)
  • @Protector one:可能,但只有当它是局部变量时才堆栈内存(在大多数情况下;特定于实现)。
【解决方案2】:

在我看来,这是一个非常糟糕的主意。老实说,如果您在 getter 中有需要定期执行的逻辑,请将其从 getter 中取出并将其粘贴到方法中。我不想跳入并维护这样的代码,一旦我终于弄清楚为什么它正在做它所做的事情,我会重构它。

【讨论】:

  • 其实大部分代码只需要执行一次——这是一个类似单例模​​式的场景。
  • @Protector:这是将单独执行的代码放在构造函数中的一个很好的论据。
  • 最多执行一次,但不一定要执行一次。这就是为什么我不想在构造函数中使用它。
【解决方案3】:

如果您可以选择,我会将 getter 中的代码提取到一个函数中,然后从 getter 和轮询器中调用该函数。

【讨论】:

  • 这可能是比 Jon Skeet 的答案更好的解决方案,但他更好地回答了这个问题。
【解决方案4】:

在变量中捕获它是最好的方法 - 不会引起任何副作用,除非 getter 本身会引起副作用。

var value = someObj.Property;

【讨论】:

  • 确实如此,但至少它不是一个没有其他用途的全局函数。 ;)
  • 确实是很简单的代码,但我觉得很浪费内存。
  • 仅供参考。它可能是一些原始类型,但无论哪种方式都不会占用大量内存。同时,您正在执行哪种类型的编程来捕获变量中的某些内容会导致性能问题?
  • 这不是问题(简单地使用ToString 也不会),我只是好奇是否没有更清洁、更简单的方法。
【解决方案5】:

我希望我理解正确。 首先

class MyClass
{
   public int Number{get;set;}
}

var cl = new MyClass();
cl.Number.ToString();

ToString() 不一定返回值,对于原语是这种情况,是的,但对于其他更复杂的类,它通常只是完整的限定名称。我猜这不是你想要的。

要执行 getter,您需要一些反射。

var propInfo = this.GetType().GetProperty("Number");
int val = (int)propInfo.GetValue(cl, null);

【讨论】:

    【解决方案6】:

    我喜欢 Jon Skeet 的回答,但同样,这也可以在无需编写扩展方法的情况下工作:

    GC.KeepAlive(instance.SomeProperty);
    

    KeepAlive 方法接受 object 并且不使用它,就像 NoOp 扩展方法一样。

    【讨论】:

    • 不,有一个重要的区别 - 它将装箱任何值类型的值。我也不确定GC.KeepAlive(null) 做了什么。
    【解决方案7】:

    我认为您需要将代码移动到其他地方。因此,请尝试在“实例”对象的构造函数中设置全局变量。

    或者.. (不确定你所说的全局变量是什么意思)但如果它在一个对象中,那么你可以获取全局对象上属性的 getter 来进行延迟加载并获取值。

    string _myProp;
    public string MyProp
    { 
       get
       {
         if (String.IsNullOrWhiteSpace(_myProp))
         {
            _myProp =  GetTheValueFromWhereEver();
         }
         return _myProp;
       }
    }
    

    (但您可能无法访问那里的“实例”)

    【讨论】:

    • 这段代码其实和我的代码很相似!那么您将如何轮询您的MyProp 属性以确保设置了_myProp? (这就是我要问的。)
    • @protector - 不,我建议将该代码放在全局级别或从实例的构造函数设置全局变量。我认为让 getter 做的不仅仅是返回一个值是不好的做法。对不起。
    • 但我不希望使用对象的 每个 实例执行属性获取器代码。而且您不必感到抱歉-您可能是对的!但我仍然有兴趣知道如何按照我的方式去做。
    • @Protector - 您可以将成员定义设为静态。
    【解决方案8】:

    尽管这可能仍然是个坏主意,但我只想留下这个简洁的 lambda 解决方案:

    ((Func< [TYPE_OF_PROPERTY] >)(() => instance.Property))();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-07
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      • 2014-08-16
      • 1970-01-01
      • 2011-12-05
      相关资源
      最近更新 更多