在我的应用程序中,我需要引用各种类型的Action
Action action1;
Action<int> action2;
Action actRef = action2; // Error: actRef is not the same type as action2
基本上我想要一种可以引用action1
和action2
的类型。这可能吗?
我能想到的最佳解决方案是将Action<...>
包装在另一个实现某个接口的类中。
public interface MyInterfaceType
{
}
public class MyActionWrapper : MyInterfaceType
{
public Action MyAction { get; set; }
}
public class MyActionWrapper<T> : MyInterfaceType
{
public Action<T> MyAction { get; set; }
}
然后随身携带对MyInterfaceType
的引用。
public class MyActionsHolder
{
List<MyInterfaceType> MyActions { get; set; }
public void DoActions()
{
foreach(MyInterfaceType anAction in MyActions)
{
if(anAction is MyActionWrapper)
((MyActionWrapper)anAction).MyAction();
else if(anAction is MyActionWrapper<int>)
((MyActionWrapper<int>)anAction).MyAction(1);
}
}
}
有更好的解决方案吗?还是一种清理这个解决方案的方法?
有关具体细节的更多背景知识。我编写了一个简单的脚本语言,我试图将其解析为Action
,每个Action
代表一个来自脚本的解析命令。正如一位评论员指出的那样,我可以轻松地将Action
与另一个
Action myParameterlessAction = new Action(() => MySingleParmAction(1));
虽然我的一些命令允许用户提供伪造的参数/变量。例如,我可能有一个允许一个参数的参数FOO
。参数可以是FOO
的值,也可以是&#34;变量&#34;表示执行命令时FOO
的当前值。
FOO 231 // Set FOO = 231
FOO VAL_FOO // Set FOO to the desired value of FOO, whatever it may be at this time
因此,当我去解析第二种类型的命令时,我创建了一个Action
,它接受一个参数,以便我可以在时机到来时提供它。
Action fooCommand1 = new Action(delegate() { MyForm.SetFooValue(231); });
Action<int> fooCommand2 = MyForm.SetFooValue;
我希望能够收集所有Action
创建解析成List<...>
然后我可以循环并执行每个动作..(我确实知道我需要一个方法来确定提供哪些Action
需要的参数以及如何确定提供给他们的内容;根据我上面的解决方案,此信息最有可能在MyInterfaceType
中。
编辑:为了回应@The Anathema的回答,我用我的语言命令允许用户等待一段时间再继续。将脚本解析为Action
看起来像这样
public KeyValuePair<Delegate, object[]> CommandAction { get; set; }
...
Action commandDelegate = new Action(async delegate()
{
await Task.Delay(msWait);
});
result.CommandAction = new KeyValuePair<Delegate, object[]>(commandDelegate, null);
在Action.DynamicInvoke
完成之前,Task.Delay(...)
会阻止吗?在当前线程或创建Action
的线程上,调用将在何处发生?我可以更改其中任何一个选项吗?
同样根据这个SO answer,我认为尝试解决Action
无参数的Action myAct
是值得的,这样我就可以Invoke
而不是DynamicInvoke
DynamicInvoke
(看到// ==UserScript==
// @name TL momentjs
// @namespace http://tampermonkey.net/
// @version 0.1
// @description add moment js to tl!
// @author You
// @match http://www.teamliquid.net/forum/
// @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.js
// @grant none
// ==/UserScript==
/* jshint -W097 */
'use strict';
// Your code here...
$('.forumindex:nth-child(3n+4)').each(function(function() {
datestr = $(this)[0].innerText.split(",")[0];
user = $(this)[0].innerText.split(",")[1];
console.log( $(this)[0].innerText = moment(datestr).fromNow() + ", " + user);
});
根据链接的答案执行的时间要长几个数量级?)
答案 0 :(得分:2)
您可以将其引用为Delegate
类型。
Delegate action1 = new Action(DoStuff);
Delegate action2 = new Action<int>(DoStuff2);
你甚至可以迭代IEnumerable<Delegate>
并动态调用它们:
var myActions = new List<Delegate>();
myActions.Add(action1);
myActions.Add(action2);
foreach (var action in myActions)
{
action.DynamicInvoke();
}
但是,请记住,如果您在没有传递给DynamicInvoke()方法的适当参数的情况下调用一个TargetParameterCountException
,您将获得 Delegate action1 = new Action(DoStuff);
Delegate action2 = new Action<int>(DoStuff2);
var myActions = new Dictionary<Delegate, object[]>();
myActions.Add(action1, null);
myActions.Add(action2, new object[] { 0 });
foreach (var action in myActions)
{
action.Key.DynamicInvoke(action.Value);
}
。
您可以更进一步,拥有一个存储参数的字典。
Dictionary<Delegate, object[]>
如果您需要多次调用相同的操作,请将List<KeyValuePair<Delegate, object[]>>
更改为using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace MVCTest.Models
{
[Table("Employee")]
public class EmployeeModel
{
public int EmployeeId { get; set; }
public string name {get;set;}
}
}
。这将允许您有重复的键(操作)。