我正在使用预先构建的第三方类库(想想.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,但我认为提出上述主要问题会更有效。
答案 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线程上触发的计时器,该竞争条件不存在,并且可以省略空检查。