C# 为字符串调用适当的方法
这本身就有一个游戏开发项目,但它实际上是关于编码和将数据映射到其他数据块。这就是为什么我决定把它贴在这里 我用于外部库存项目数据存储的格式:C# 为字符串调用适当的方法,c#,methods,C#,Methods,这本身就有一个游戏开发项目,但它实际上是关于编码和将数据映射到其他数据块。这就是为什么我决定把它贴在这里 我用于外部库存项目数据存储的格式: [ID:IT_FO_TROUT] [Name:Trout] [Description:A raw trout.] [Value:10] [3DModel:null] [InventoryIcon:trout] [Tag:Consumable] [Tag:Food] [Tag:Stackable] [OnConsume:RestoreHealth(15
[ID:IT_FO_TROUT]
[Name:Trout]
[Description:A raw trout.]
[Value:10]
[3DModel:null]
[InventoryIcon:trout]
[Tag:Consumable]
[Tag:Food]
[Tag:Stackable]
[OnConsume:RestoreHealth(15)]
[OnConsume:RestoreFatigue(15)]
问题集中在最后2个消费属性上。基本上,这两个属性意味着当物品被消费时,消费者的健康水平会提高15分,他的疲劳程度也会提高。这在后台调用了两种不同的方法:
void RestoreHealth(Character Subject, int Amount);
void RestoreFatigue(Character Subject, int Amount);
您将如何将这些方法映射到它们在文件字符串中的对应项?这就是我的想法:
映射
public interface IConsumeEvent
{
void ApplyConsumeEffects(BaseCharacter Consumer);
}
示例实现者(特定事件):
在解析器内部(我们唯一关心事件特殊性的地方——因为我们正在解析数据文件本身):
当角色使用某个项目时:
foreach (IConsumeEvent ConsumeEvent in Item.ConsumeEvents)
{
//We're inside a parent method that's inside a parent BaseCharacter class; we're consuming an item right now.
ConsumeEvent.ApplyConsumeEffects(this);
}
为什么不将它们“映射”到“命令”类一次,而且只映射一次呢
比如说,
[OnConsume:RestoreHealth(15)]
[OnConsume:RestoreFatigue(15)]
可以映射到RestoreHealth
和RestoreFatigue
命令类,这些命令类可以定义为:
public sealed class RestoreHealth : ICommand {
public int Value { get; set; }
//whatever else you need
}
public sealed class SummonMonster : ICommand {
public int Count {get; set; }
public Position Position { get; set; }
}
此时,将命令视为参数的包装;)因此,与传递多个参数不同,您总是将它们包装起来,只传递一个参数。
它还提供了一些语义
现在,您可以将库存项目映射到需要在每个项目消耗时“发送”的命令
您可以实现一个简单的“总线”接口,如:
public interface IBus {
void Send(ICommand command);
void Subscribe(object subscriber);
}
现在,您只需获得IBus
的一个实例,并在适当的时候调用其Send
方法
通过这样做,您可以分离您的“定义”(需要做什么)和您的逻辑(如何执行操作)关注点
对于接收和反应部分,您实现了Subscribe
方法来询问subscriber
实例(再次、一次且仅一次),找出其所有可以“处理”命令的方法。
您可以在处理程序中找到一些i处理程序,其中T:ICommand
接口,或者按照约定查找它们(任何Handle
方法,只接受ICommand
的一个参数并返回void
),或者任何适合您的方法
它基本上与您刚才提到的“委托/操作”列表相同,只是现在它是每个命令的:
您已经有一个类负责保存InventoryItem和命令之间的映射,因此该类可以成为流程管理器:
ConsumeItem
命令(通过总线)Handle
方法中,它获取给定库存项目的命令列表ConsumeItem
命令,我们不关心接下来会发生什么李>
IBus',订阅ConsumeItem`命令,并且“知道”在消费每个项目时需要做什么(命令列表)。它只发送这些命令,而不关心谁和如何处理它们
RestoreHealth
、Die
,等等),而不关心它们来自何处(以及为什么)祝你好运:)我的建议是使用反射,即定义一个基于指定名称调用所需方法的方法。下面是一个工作示例:
class Program
{
static void Main(string[] args)
{
SomeClass someInstance = new SomeClass();
string name = Console.ReadLine();
someInstance.Call("SayHello", name);
}
}
class SomeClass
{
public void SayHello(string name)
{
Console.WriteLine(String.Format("Hello, {0}!", name));
}
public void Call(string methodName, params object[] args)
{
this.GetType().GetMethod(methodName).Invoke(this, args);
}
}
如果满足以下条件,您可以这样做:
public interface IBus {
void Send(ICommand command);
void Subscribe(object subscriber);
}
map<CommandType, List<action>>
public sealed void ConsumeItem: ICommand {
public InventoryItem Item { get; set; }
}
class Program
{
static void Main(string[] args)
{
SomeClass someInstance = new SomeClass();
string name = Console.ReadLine();
someInstance.Call("SayHello", name);
}
}
class SomeClass
{
public void SayHello(string name)
{
Console.WriteLine(String.Format("Hello, {0}!", name));
}
public void Call(string methodName, params object[] args)
{
this.GetType().GetMethod(methodName).Invoke(this, args);
}
}
public void Call(string methodName, params object[] args)
{
//get the method with the specified name and parameter list
Type[] argTypes = args.Select(arg => arg.GetType()).ToArray();
MethodInfo method = this.GetType().GetMethod(methodName, argTypes);
//check if the method exists and invoke it
if (method != null)
method.Invoke(this, args);
}
public static class Extensions
{
//invoke a method with the specified name and parameter list
// and return a result of type T
public static T Call<T>(this object subject, string methodName, params object[] args)
{
//get the method with the specified name and parameter list
Type[] argTypes = args.Select(arg => arg.GetType()).ToArray();
MethodInfo method = subject.GetType().GetMethod(methodName, argTypes);
//check if the method exists
if (method == null)
return default(T); //or throw an exception
//invoke the method and get the result
object result = method.Invoke(subject, args);
//check if something was returned
if (result == null)
return default(T); //or throw an exception
//check if the result is of the expected type (or derives from it)
if (result.GetType().Equals(typeof(T)) || result.GetType().IsSubclassOf(typeof(T)))
return (T)result;
else
return default(T); //or throw an exception
}
//invoke a void method more conveniently
public static void Call(this object subject, string methodName, params object[] args)
{
//invoke Call<object> method and ignore the result
subject.Call<object>(methodName, args);
}
}