【发布时间】:2011-09-15 16:20:57
【问题描述】:
在下面的方法中,我发送了一个动作枚举,并希望返回一个 ICommand 数组,调用 Action<object> 来包装这些动作(relayCommand 需要)。
问题是,如果我在 for each(甚至是 for 循环)中执行此操作,我会得到始终执行参数中传递的第一个操作的命令。
public static ICommand[] CreateCommands(IEnumerable<Action> actions)
{
List<ICommand> commands = new List<ICommand>();
Action[] actionArray = actions.ToArray();
// works
//commands.Add(new RelayCommand(o => { actionArray[0](); })); // (_execute = {Method = {Void <CreateCommands>b__0(System.Object)}})
//commands.Add(new RelayCommand(o => { actionArray[1](); })); // (_execute = {Method = {Void <CreateCommands>b__1(System.Object)}})
foreach (var action in actionArray)
{
// always add the same _execute member for each RelayCommand (_execute = {Method = {Void <CreateCommands>b__0(System.Object)}})
commands.Add(new RelayCommand(o => { action(); }));
}
return commands.ToArray();
}
似乎 lambda 总是在循环内被重用,认为它做同样的事情,但事实并非如此。
我该如何克服这种情况?
我怎样才能强制循环威胁o => { action(); } 总是作为一个新的?
谢谢!
我按照建议尝试了,但没有帮助:
foreach (var action in actionArray)
{
Action<object> executeHandler = o => { action(); };
commands.Add(new RelayCommand(executeHandler));
}
似乎对我有用的是:
class RelayExecuteWrapper
{
Action _action;
public RelayExecuteWrapper(Action action)
{
_action = action;
}
public void Execute(object o)
{
_action();
}
}
/// ...
foreach (var action in actionArray)
{
RelayExecuteWrapper rxw = new RelayExecuteWrapper(action);
commands.Add(new RelayCommand(rxw.Execute));
}
RelayCommand代码:
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
【问题讨论】:
-
你为什么不直接“foreach”操作?
-
你打电话给
.ToArray()有什么原因吗?看来您可以只遍历IEnumberable<Action>并节省一些时间。 -
它不会改变任何东西,这里有代码通过给出显式索引来测试它是否有效,并且它在这种情况下有效......
-
你为什么不返回 List
或将命令设为 ICommand[] -
我对这些问题有点厌烦了,请尽量保持专注,问题不在于 .toArray() 或 ToList(),循环内的东西是......我会的如果我让它工作,请进行重构
标签: c# .net loops lambda language-features