我可以在构造函数调用中将对象的状态设置为对象本身吗?

时间:2013-10-31 11:45:26

标签: c# constructor

我正在使用预先构建的第三方类库(想想.NET Framework ...),其中包含具有以下成员的类Foo

public sealed class Foo {
  private object _state;
  public Foo(object state) { _state = state; }
}

Foo 包含public _state二传手。

在特定场景中,我想将Foo对象的状态设置为对象本身。

这将 NOT 编译:

Foo f;
f = new Foo(f);   // Compilation error: Use of unassigned local variable 'f'

鉴于上述先决条件,是否有任何方式可以将Foo对象的状态设置为对象本身?


基本原理 Windows 8.1中的Timer类不包含Timer(AsyncCallback)构造函数,该构造函数为对象本身分配了Timer对象的状态。我试图将包含此Timer构造函数的.NET代码移植到Windows 8.1类库中,所以我关注的是如何将对象本身传递给其状态成员?这个问题进一步概述here,但我认为提出上述主要问题会更有效。

4 个答案:

答案 0 :(得分:2)

解决方法:

var foo = new Foo(/*params*/);
var fieldInfo = foo.GetType().GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(foo , foo);

答案 1 :(得分:2)

如果我理解你的意图,你想要一个定时器,其回调引用定时器本身。

Timer timer = null;
timer = new Timer(() => {
 timer.Stop(); //sample
});

创建对象是通过newobj指令完成的,该指令以原子方式分配并调用构造函数。如果没有ctor的合作,你就无法获得对未构造对象的引用。所以这种方法或反思没有别的办法。

你可以将上面的代码提取到一个辅助方法中,使timer成为一个局部变量,然后每个定时器回调将关闭它自己的私有和不变的变量。

Timer CreateTimer(Action<Timer> callback) {
    Timer timer = null;
    timer = new Timer(() => {
     callback(timer);
    });
}

答案 2 :(得分:1)

只有Foo,这是不可能的。您可以引入一个facade / proxy对象并将其传递给构造函数代码,这样就可以解决问题:

public class FooFacade  {
    private Foo foo;
    public void SetFoo(Foo f) { foo = f; }

    // for each property:
    public X Y { get { return foo.Y; } }
}

然后你可以使用这个门面:

FooFacade ff = new FooFacade();
Foo f = new Foo(ff);
ff.SetFoo(f);

当然,这不是你想要的。这种尝试的缺点是对象的状态仅限于它的公开表示。

反思,只是为了完整性:

// create an uninitialized object of type Foo, does not call constructor:
var f = (Foo)FormatterServices.GetUninitializedObject(typeof(Foo));

// get field:
var stateField = typeof(Foo).GetField("_state", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);

// set value to instance itself, invoke on f:
stateField.SetValue(f, f);

答案 3 :(得分:0)

据我了解,您不想将对象本身作为构造函数参数传递;你想传递一个取决于对象的lambda。这是对的吗?

在这种情况下,一个不太可行但可行的解决方法是添加一个间接层:

Action callback = null;
var timer = new Timer(() => {
    if (callback != null)
        callback();
});
callback = () => {
    // do something
    // do something with timer
}

所以你要将lambda传递给构造函数 - lambda在你调用构造函数时是有效的,尽管它对调用它无效它取决于所设置的callback变量。然后,您立即将callback变量设置为您想要的实现,现在可以安全地引用timer

如果您正在使用在后台线程上触发的计时器,那么可能存在竞争条件,计时器可能会在您将callback变量初始化为非空值之前触发;因此在lambda中进行空检查。对于在UI线程上触发的计时器,该竞争条件不存在,并且可以省略空检查。