当委托是匿名的并且及时创建包含类作为函数的参数时,我正在努力理解如何在动作委托中访问本地类变量。
委托似乎可以访问调用函数变量,它包含类,但不能访问实际包含委托的类。如果我不清楚我的问题,请原谅我,我正尽力表达清楚。请参考以下代码:
public class QueryPropertyMessage
{
public Action Callback { get; private set; }
public string PropertyName { get; set; }
public object PropertyValue { get; set; }
public QueryPropertyMessage(Action callback)
{
this.Callback = callback;
}
}
Class TestClass
{
public void OuterTestFunction()
{
//the function will set PeropertyValue
SomeClass.FunctionAcceptingQueryPropertyMessageObject (new QueryPropertyMessage (() =>
{
Helper.DebugHelper.TraceMessage ("Test Anonymous method");
//Error The name 'PropertyValue' does not exist in the current context
If(PropertyValue!=null)
var val = Convert.ChangeType (PeropertyValue, typeof (bool));
}) { PropertyName = "SomeBooleanProperty" });
}
}
如何在匿名委托中访问QueryPropertyMessage对象的属性? 在匿名方法上阅读Raymond Chen's article,我似乎认为委托将被包装在另一个辅助类中,因此看起来像包含类(QueryPropertyMessage)的东西不是代理角度的本地类。我希望能更清楚地理解它。
答案 0 :(得分:1)
这样做有点痛苦。你基本上需要声明一个局部变量,给它一个临时值(这样它是明确分配的),然后使用那个局部变量:
QueryPropertyMessage message = null;
message = new QueryPropertyMessage(() =>
{
// Use message in here
});
SomeClass.FunctionAcceptingQueryPropertyMessageObject(message);
这依赖于在构造函数中调用回调而不是 - 否则它会看到null
的原始message
值。
(或者,您可以更改回调以接收消息。)
答案 1 :(得分:1)
需要在创建QueryPropertyMessage
之前创建操作,甚至已定义,以便您能够将其传递到其构造函数中。因此,在那个时间点没有任何内容可供参考。您需要首先为相关对象创建或至少定义变量。
QueryPropertyMessage message = new QueryPropertyMessage();
message.Callback = () =>
{
var propertyName = message.PropertyName;
};
(这当然需要一个无参数构造函数和一个用于回调的setter。)
如果您不想修改类,那么您只能定义变量而不是初始化变量:
QueryPropertyMessage message = null;
message = new QueryPropertyMessage(() =>
{
var propertyName = message.PropertyName;
});
那,或者你需要将对象本身作为参数传递给动作:
public class QueryPropertyMessage
{
public Action<QueryPropertyMessage> Callback { get; private set; }
public string PropertyName { get; set; }
public object PropertyValue { get; set; }
public QueryPropertyMessage(Action<QueryPropertyMessage> callback)
{
this.Callback = callback;
}
}
new QueryPropertyMessage(props =>
{
var propertyName = props.PropertyName;
});
答案 2 :(得分:1)
你不能这样做。代表不知道它被传递给构造函数。这就像int
知道包含它的类型一样。
解决此问题的一种方法是公开你的setter,创建QueryPropertyMessage
的实例,然后设置委托。
var query = new QueryPropertyMessage();
query.Callback = () =>
{
Helper.DebugHelper.TraceMessage ("Test Anonymous method");
If(query.PropertyValue!=null)
var val = Convert.ChangeType (PeropertyValue, typeof (bool));
};
这样,lambda将关闭您的QueryPropertyMessage
实例,并可以访问它。
我似乎认为委托将包装在另一个帮助类
中
仅当它需要关闭(查找闭包)一个或多个变量时。在上面的代码中,这将会发生。
编译器将创建一个将QueryPropertyMessage
实例作为字段的类,以及一个实现lambda的方法,如下所示:
public class <Lambda>b__0
{
private readonly QueryPropertyMessage _query = ...
public void Execute()
{
Helper.DebugHelper.TraceMessage ("Test Anonymous method");
If(_query.PropertyValue!=null)
var val = Convert.ChangeType (PeropertyValue, typeof (bool));
}
}
答案 3 :(得分:0)
您的问题的解决方案是您需要更改操作&lt;&gt;输入Action<QueryPropertyMessage>
回拨
class QueryPropertyMessage
{
public Action<QueryPropertyMessage> Callback { get; private set; }
public string PropertyName { get; set; }
public object PropertyValue { get; set; }
public QueryPropertyMessage(Action<QueryPropertyMessage> callback)
{
this.Callback = callback;
}
}
public class TestClass
{
public void OuterTestFunction()
{
//the function will set PeropertyValue
SomeClass.FunctionAcceptingQueryPropertyMessageObject (new QueryPropertyMessage ((item) =>
{
Helper.DebugHelper.TraceMessage ("Test Anonymous method");
//Error The name 'PropertyValue' does not exist in the current context
If(item.PropertyValue!=null)
var val = Convert.ChangeType (PeropertyValue, typeof (bool));
}) { PropertyName = "SomeBooleanProperty" });
}
}
}