我希望在进行异步操作时使用列表作为向框架存储操作 然后,当框架同步时,我将循环列表并执行操作。
有没有办法做到这一点,重点关注:
- No Reflection / DynamicInvoke
- 不为每个要调用的新方法创建类/结构
- 输入安全。
- 将操作存储在列表中
- 存储不同种类的方法和参数
- 稍后执行列表。
我不想使用反射的原因是因为它是一个性能问题。它会经常使用。
在这种情况下,它与游戏相关,但代码可以用作全部,并且如果可以避免使用reflection / DynamicInvoke,则对于多线程非常有用。
如果这是不可能的,那么还有其他不错的选择吗?
我在代码中做了一个例子,但是它使用了反射并且不是类型安全的
基本上步骤是:
1.使用具有多个不同参数的方法填充列表
2.循环列表&用参数执行所有方法
3.清除下一个循环的列表。
{
struct MyDelayedCaller
{
public Delegate TheTarget;
public object[] MyParameters;
public MyDelayedCaller(Delegate target, object[] parameters)
{
TheTarget = target;
MyParameters = parameters;
}
}
List<MyDelayedCaller> Temporary = new List<MyDelayedCaller>();
void Update()
{
//something happened and another class needs to know
//but it will have to wait for the sync so as to not cause any treading problems
Temporary.Add(new MyDelayedCaller(new DelDoSomething1(DoSomething1), new object[] { 10, false }));
Temporary.Add(new MyDelayedCaller(new DelDoSomething1(DoSomething1), new object[] { 11, true }));
Temporary.Add(new MyDelayedCaller(new DelDoSomething3(DoSomething3), new object[] { "Some text" }));
Temporary.Add(new MyDelayedCaller(new DelDoSomething2(DoSomething2), new object[] { 1, 9999, 0.4f }));
}
void Sync()
{
foreach (var item in Temporary)
{
item.TheTarget.DynamicInvoke(item.MyParameters);
}
Temporary.Clear();
}
delegate void DelDoSomething1(int index, bool alive);
void DoSomething1(int index, bool alive)
{
}
delegate void DelDoSomething2(int index, int amount, float scale);
void DoSomething2(int index, int amount, float scale)
{
}
delegate void DelDoSomething3(string text);
void DoSomething3(string text)
{
}
}
答案 0 :(得分:2)
我希望我理解这个问题,因为答案看起来很简单:只需存储一个List<Action>
。你可以在那里放任何你想要的东西。您可以枚举列表并调用所有内容。
您绝对可以将参数化调用添加到此类列表中:() => DoSomething1(10, false)
。参数打包在Action
内。 C#编译器生成一个(强类型)闭包类,并为您完成所有这些。
这不是你想做的吗?
答案 1 :(得分:0)
我会跟随以下内容:
IMyDelayedCaller
界面:
interface IMyDelayedCaller
{
void Invoke();
}
一组MyDelayedCaller
泛型类:
class MyDelayedCaller<T1> : IMyDelayedCaller
{
private Action<T1> _target;
public T1 _param;
public MyDelayedCaller(Action<T1> target, T1 parameter)
{
_target = target;
_param = parameter;
}
public void Invoke()
{
_target(_param);
}
}
class MyDelayedCaller<T1, T2> : IMyDelayedCaller
{
private Action<T1, T2> _target;
public T1 _param1;
public T2 _param2;
public MyDelayedCaller(Action<T1, T2> target, T1 param1, T2 param2)
{
_target = target;
_param1 = param1;
_param2 = param2;
}
public void Invoke()
{
_target(_param1, _param2);
}
}
我只展示了最多2个参数,如果需要,你可以赚更多。
将您的列表更改为List<IMyDelayedCaller>
:
List<IMyDelayedCaller> Temporary = new List<IMyDelayedCaller>();
使用编译时类型安全性将项添加到列表中:
Temporary.Add(new MyDelayedCaller<int, bool>(DoSomething1, 10, true));
Temporary.Add(new MyDelayedCaller<string>(DoSomething3, "Some text"));
使用界面方法调用:
foreach (var item in Temporary)
{
item.Invoke();
}
Temporary.Clear();
您可以通过提供静态类来使停止4.更容易,这将允许编译器推断您的类型参数:
static class MyDelayedCaller
{
public static MyDelayedCaller<T1> Create<T1>(Action<T1> target, T1 param)
{
return new MyDelayedCaller<T1>(target, param1);
}
public static MyDelayedCaller<T1, T2> Create<T1, T2>(Action<T1, T2> target, T1 param1, T2 param2)
{
return new MyDelayedCaller<T1, T2>(target, param1, param2);
}
}
和用法:
Temporary.Add(MyDelayedCaller.Create(DoSomething1, 10, true));
Temporary.Add(MyDelayedCaller.Create(DoSomething3, "Some text"));
答案 2 :(得分:0)
You could queue up your inputs and actions in parallel collections:
var actions = new Dictionary<int, Func<object[], object>>();
var inputs = new Dictionary<int, object[]>();
//when you want to store the action and it's input
int counter = 0;
object[] someObjects = new object[] {};
actions.Add(counter, x => { return x[0]; });
inputs.Add(counter, someObjects);
counter++;
//and then later when it's time to execute
foreach (var input in inputs)
{
actions[input.Key].Invoke(input.Value);
}
或者,您可以滚动一个存储输入和操作的类,因此输入在执行时通过匹配的字典键以外的其他操作耦合到操作。
答案 3 :(得分:0)
我的另一个答案显示了相当复杂的方法。然而,有一个更容易。你为什么不列出你的名单List<Action>
?
List<Action> Temporary = new List<Action>();
void Update()
{
//something happened and another class needs to know
//but it will have to wait for the sync so as to not cause any treading problems
Temporary.Add(() => DoSomething1(1, true));
Temporary.Add(() => DoSomething3("Some text"));
}
void Sync()
{
foreach (var item in Temporary)
{
item.Invoke();
}
Temporary.Clear();
}
应该工作得很好。
答案 4 :(得分:0)
@Eli,你在for循环中输入4作为输入值,因为动作的执行是延迟的。当它们实际执行时,i = 4;
要避免这种情况,请排列输入。
我会以评论回复你的评论,但还没有代表。