除了对象实例之外,我还可以使用什么可传递的值来访问多个函数?
What passable value can I use, besides an object instance, to access multiple functions?
我正在学习 C#,我正在寻找一个问题的解决方案,该问题可能是由糟糕的体系结构引起的,并且不会影响实际程序。
我想传"something"(不一定是class),它有多个函数,不需要实例化,比如我想有一个class在字典中列出了时间和任务,例如,在 12:00 我想要 class 到 'lunch',但是午餐可能取决于其他变量,所以我有一个dict entry to check like {12, LunchTask}, LunchTask is subclass/implementation/derivation of 'Task' 所以我们可以安全地传递它并调用类似 SomeTask.Start, SomeTask.Pause, SomeTask.Stop.
我想使用 Dictionary (int,System.Type) 但无法让它工作,我也尝试过静态,但它们不能被 subclassed 并且委托用于单个函数据我所知。我只想在 dict 中传递一些东西,它具有可以直接访问而无需实例化的功能。我知道一种解决方案可行但我发现非常不雅的是使用静态 class 包含所有不同任务的实例。
我不知道有什么更好的方法来实现这样的基本功能,也许我做的每件事都大错特错。因此,如果你们能指出我正确的方向,我将不胜感激。提前谢谢你。
这是一些(伪 C#)代码:
public abstract class Task {
public abstract void ExecuteTask ();
public virtual void PauseTask() {Console.WriteLine ("Task Paused")}
public virtual void StopTask() {Console.WriteLine ("Task Stopped")}
}
public class Lunch : Task {
public override void ExecuteTask ()
{
Console.WriteLine ("Lunch Task Started");
}
}
//the following is gonna be instantiated
public class Human {
Dictionary<int, Something> attributions = new Dictionary<int, Something>(){{12, Lunch}};
void ToBeCalledEveryHour () {
int hour = someHour();
if (attributions.ContainsKey(hour))
attributions[hour].ExecuteTask();
}
}
如果您的方法的参数始终相同,这是一件很简单的事情。
但是,如果它们要有所不同,这将非常困难。
我会说,与仅在 Dispatcher 外部实例化您想要的对象并在其内部调用方法相比,我认为这并没有太大优势。
但这是您要实现的目标的一个非常基本的示例(根据您发布的代码进行了编辑):
//Method Call:
Dictionary<int, System.Type> attributions = new Dictionary<int, System.Type>(){{12, typeof[Lunch]}};
Dispatcher(attributions);
//Dispatcher
public void Dispatcher(IDictionary<int, System.Type> dictionary) {
int hour = SomeHour()
// Instantiate object
var obj = Activator.CreateInstance(attributions[hour]);
//Build args
var args = new object[]{
new object(),
};
// Invoke method
type.InvokeMember("ExecuteTask", System.Reflection.BindingFlags.Public, null, obj, args);
}
您可以使用类似下面的内容来存储函数字典,其中每个函数都具有相同的签名。
然后您可以传递对此类字典的引用。您还可以将对静态 Compute 方法的引用传递给任何接受 Func
的方法
internal enum ArithmeticFunction
{
Add,
Subtract,
Multiply,
Divide,
Min,
Max,
}
internal static class FunctionMap
{
private static readonly Dictionary<ArithmeticFunction, Func<int, int, int>> s_map;
static FunctionMap()
{
s_map = new Dictionary<ArithmeticFunction, Func<int, int, int>>();
s_map[ArithmeticFunction.Add] = (x, y) => x + y;
s_map[ArithmeticFunction.Subtract] = (x, y) => x - y;
s_map[ArithmeticFunction.Multiply] = (x, y) => x * y;
s_map[ArithmeticFunction.Divide] = (x, y) => x / y;
s_map[ArithmeticFunction.Min] = System.Math.Min;
s_map[ArithmeticFunction.Max] = System.Math.Max;
}
//Don't allow callers access to the core map. Return them a copy instead.
internal static Dictionary<ArithmeticFunction, Func<int, int, int>> GetCopy()
{
return new Dictionary<ArithmeticFunction, Func<int, int, int>>(s_map);
}
internal static int Compute(ArithmeticFunction op, int x, int y)
{
return s_map[op](x, y);
}
}
static void Main(string[] args)
{
System.Diagnostics.Trace.WriteLine("Example 1:");
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Add, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Subtract, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Multiply, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Divide, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Min, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Max, 12, 4));
var safeCopy = FunctionMap.GetCopy();
System.Diagnostics.Trace.WriteLine("Example 2:");
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Add](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Subtract](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Multiply](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Divide](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Min](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Max](72, 9));
输出如下:
Example 1:
16
8
48
3
4
12
Example 2:
81
63
648
8
9
72
在您的情况下,您可以使用对象池模式或工厂模式。
如果是对象池模式,你可以有一个映射,其中键应该是唯一标识对象的字符串,例如它可以是 class 名称,值可以是相应的对象。
像这样:
public abstract class Task {
public abstract void ExecuteTask ();
public virtual void PauseTask() {Console.WriteLine ("Task Paused")}
public virtual void StopTask() {Console.WriteLine ("Task Stopped")}
}
public class Lunch : Task {
public override void ExecuteTask ()
{
Console.WriteLine ("Lunch Task Started");
}
}
public class ObjectCollection{
Dictionary<string,Task> objectStringMapper= new Dictionary<string,string>();
Dictionary<string,Task> objectTimeMapper= new Dictionary<string,string>();
public ObjectCollection(){
objectMapper.Add("Lunch",new LunchTask());
objectTimeMapper.Add(12,new LunchTask());
}
public Task getObject(string objId){
return objectMapper.get(objId);
}
public Task getObject(int time){
return objectTimeMapper.get(time);
}
}
public class Human {
ObjetCollection objectsFactory = new ObjectCollection();
void ToBeCalledEveryHour () {
int hour = someHour();
if (attributions.ContainsKey(hour))
objectsFactory.getObject(hour).ExecuteTask();
}
}
或者您可以选择工厂模式,在该模式中您可以 class 使用反射或开关盒创建对象。
注意:由于我是一名 Java 开发人员并且是 c# 的新手,您可能会发现某些语法错误。
我正在学习 C#,我正在寻找一个问题的解决方案,该问题可能是由糟糕的体系结构引起的,并且不会影响实际程序。
我想传"something"(不一定是class),它有多个函数,不需要实例化,比如我想有一个class在字典中列出了时间和任务,例如,在 12:00 我想要 class 到 'lunch',但是午餐可能取决于其他变量,所以我有一个dict entry to check like {12, LunchTask}, LunchTask is subclass/implementation/derivation of 'Task' 所以我们可以安全地传递它并调用类似 SomeTask.Start, SomeTask.Pause, SomeTask.Stop.
我想使用 Dictionary (int,System.Type) 但无法让它工作,我也尝试过静态,但它们不能被 subclassed 并且委托用于单个函数据我所知。我只想在 dict 中传递一些东西,它具有可以直接访问而无需实例化的功能。我知道一种解决方案可行但我发现非常不雅的是使用静态 class 包含所有不同任务的实例。
我不知道有什么更好的方法来实现这样的基本功能,也许我做的每件事都大错特错。因此,如果你们能指出我正确的方向,我将不胜感激。提前谢谢你。
这是一些(伪 C#)代码:
public abstract class Task {
public abstract void ExecuteTask ();
public virtual void PauseTask() {Console.WriteLine ("Task Paused")}
public virtual void StopTask() {Console.WriteLine ("Task Stopped")}
}
public class Lunch : Task {
public override void ExecuteTask ()
{
Console.WriteLine ("Lunch Task Started");
}
}
//the following is gonna be instantiated
public class Human {
Dictionary<int, Something> attributions = new Dictionary<int, Something>(){{12, Lunch}};
void ToBeCalledEveryHour () {
int hour = someHour();
if (attributions.ContainsKey(hour))
attributions[hour].ExecuteTask();
}
}
如果您的方法的参数始终相同,这是一件很简单的事情。 但是,如果它们要有所不同,这将非常困难。
我会说,与仅在 Dispatcher 外部实例化您想要的对象并在其内部调用方法相比,我认为这并没有太大优势。
但这是您要实现的目标的一个非常基本的示例(根据您发布的代码进行了编辑):
//Method Call:
Dictionary<int, System.Type> attributions = new Dictionary<int, System.Type>(){{12, typeof[Lunch]}};
Dispatcher(attributions);
//Dispatcher
public void Dispatcher(IDictionary<int, System.Type> dictionary) {
int hour = SomeHour()
// Instantiate object
var obj = Activator.CreateInstance(attributions[hour]);
//Build args
var args = new object[]{
new object(),
};
// Invoke method
type.InvokeMember("ExecuteTask", System.Reflection.BindingFlags.Public, null, obj, args);
}
您可以使用类似下面的内容来存储函数字典,其中每个函数都具有相同的签名。
然后您可以传递对此类字典的引用。您还可以将对静态 Compute 方法的引用传递给任何接受 Func
internal enum ArithmeticFunction
{
Add,
Subtract,
Multiply,
Divide,
Min,
Max,
}
internal static class FunctionMap
{
private static readonly Dictionary<ArithmeticFunction, Func<int, int, int>> s_map;
static FunctionMap()
{
s_map = new Dictionary<ArithmeticFunction, Func<int, int, int>>();
s_map[ArithmeticFunction.Add] = (x, y) => x + y;
s_map[ArithmeticFunction.Subtract] = (x, y) => x - y;
s_map[ArithmeticFunction.Multiply] = (x, y) => x * y;
s_map[ArithmeticFunction.Divide] = (x, y) => x / y;
s_map[ArithmeticFunction.Min] = System.Math.Min;
s_map[ArithmeticFunction.Max] = System.Math.Max;
}
//Don't allow callers access to the core map. Return them a copy instead.
internal static Dictionary<ArithmeticFunction, Func<int, int, int>> GetCopy()
{
return new Dictionary<ArithmeticFunction, Func<int, int, int>>(s_map);
}
internal static int Compute(ArithmeticFunction op, int x, int y)
{
return s_map[op](x, y);
}
}
static void Main(string[] args)
{
System.Diagnostics.Trace.WriteLine("Example 1:");
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Add, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Subtract, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Multiply, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Divide, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Min, 12, 4));
System.Diagnostics.Trace.WriteLine(FunctionMap.Compute(ArithmeticFunction.Max, 12, 4));
var safeCopy = FunctionMap.GetCopy();
System.Diagnostics.Trace.WriteLine("Example 2:");
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Add](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Subtract](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Multiply](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Divide](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Min](72, 9));
System.Diagnostics.Trace.WriteLine(safeCopy[ArithmeticFunction.Max](72, 9));
输出如下:
Example 1:
16
8
48
3
4
12
Example 2:
81
63
648
8
9
72
在您的情况下,您可以使用对象池模式或工厂模式。
如果是对象池模式,你可以有一个映射,其中键应该是唯一标识对象的字符串,例如它可以是 class 名称,值可以是相应的对象。
像这样:
public abstract class Task {
public abstract void ExecuteTask ();
public virtual void PauseTask() {Console.WriteLine ("Task Paused")}
public virtual void StopTask() {Console.WriteLine ("Task Stopped")}
}
public class Lunch : Task {
public override void ExecuteTask ()
{
Console.WriteLine ("Lunch Task Started");
}
}
public class ObjectCollection{
Dictionary<string,Task> objectStringMapper= new Dictionary<string,string>();
Dictionary<string,Task> objectTimeMapper= new Dictionary<string,string>();
public ObjectCollection(){
objectMapper.Add("Lunch",new LunchTask());
objectTimeMapper.Add(12,new LunchTask());
}
public Task getObject(string objId){
return objectMapper.get(objId);
}
public Task getObject(int time){
return objectTimeMapper.get(time);
}
}
public class Human {
ObjetCollection objectsFactory = new ObjectCollection();
void ToBeCalledEveryHour () {
int hour = someHour();
if (attributions.ContainsKey(hour))
objectsFactory.getObject(hour).ExecuteTask();
}
}
或者您可以选择工厂模式,在该模式中您可以 class 使用反射或开关盒创建对象。
注意:由于我是一名 Java 开发人员并且是 c# 的新手,您可能会发现某些语法错误。