3

私は MUD に取り組んでいます。現在、コマンド ハンドラーは文字列 readString と Player PlayerObj を受け取るタプルであり、switch ステートメントを使用して戻りタプルを決定します。

public Tuple<string, Player> handleCMD(string readString, Player PlayerObj)
{
    Tuple<string, Player> returnTuple = new Tuple<string, Player>(readString, PlayerObj);
    string[] arguments = readString.Split(' ');

    switch (arguments[0].ToLower())
    {
        case "addchange":
            returnTuple = doAddChange(readString, PlayerObj);
            break;
        case "changes":
            returnTuple = doChanges(readString, PlayerObj);
            break;
        case "score":
            returnTuple = doScore(readString, PlayerObj);
            break;
        case "look":
            returnTuple = doLook(readString, PlayerObj);
            break;
        case "north":
            returnTuple = doWalk(arguments[0], PlayerObj);
            break;
        case "east":
            returnTuple = doWalk(arguments[0], PlayerObj);
            break;
        case "south":
            returnTuple = doWalk(arguments[0], PlayerObj);
            break;
        case "west":
            returnTuple = doWalk(arguments[0], PlayerObj);
            break;
        case "quit":
            returnTuple = doQuit(readString, PlayerObj);
            break;
        case "chat":
            returnTuple = doChat(readString, PlayerObj);
            break;
        case "say":
            returnTuple = doSay(readString, PlayerObj);
            break;
        case "who":
            returnTuple = doWho(readString, PlayerObj);
            break;
        case "tell":
            returnTuple = doTell(readString, PlayerObj);
            break;
        default:
            returnTuple = doHuh(readString, PlayerObj);
            break;
    }
    return returnTuple;
}

public Tuple<string, Player> doSay(string readString, Player PlayerObj)
{
    DBHandler dbHandler = new DBHandler();
    PlayerObj = dbHandler.GetPlayer(PlayerObj.PlayerName);
    string returnString;
    string[] arguments = readString.Split(' ');
    if (arguments.Count() > 1 && arguments[1] != string.Empty && arguments[1] != null && arguments[1] != "" && arguments[1] != " ")
    {
        readString = readString.Trim().Replace("say ", "");
        Message message = new Message(0, readString, PlayerObj.PlayerID, 0, 1, 1);
        returnString = string.Format("You say \"{0}\"", readString);
        foreach (int i in dbHandler.GetPlayersInRoom(PlayerObj.RoomID, PlayerObj.PlayerName))
            dbHandler.AddMessage(new Message(0, message.MessageText, message.SenderPlayerID, i, message.MessageType, message.Ticked));
    }
    else
        returnString = "[Syntax] : Say <Message>";
    return new Tuple<string, Player>(returnString, PlayerObj);
}

switch ステートメントをデータベース内のテーブルによって設定されたディクショナリに置き換えて、コードを編集せずにデータベース テーブル内のコマンド/エイリアスを追加および無効にできるようにしたいと考えています。

私はこのようにそれをやろうとしました:

public Tuple<string, Player> handleCMD(string readString, Player PlayerObj)
{
    Tuple<string, Player> returnTuple = new Tuple<string, Player>(readString, PlayerObj);
    string[] arguments = readString.Split(' ');
    DBHandler dbHandler = new DBHandler();

    Dictionary<string, Delegate> cmdDictionary = new Dictionary<string, Delegate>();

    foreach (Command playerCommand in dbHandler.GetCommands())
        cmdDictionary.Add(playerCommand.CommandName, new Func<string, Player, Tuple<string, Player>>(playerCommand.CommandTuple));
    if (cmdDictionary[arguments[0]] != null)
        returnTuple = (Tuple<string, Player>)cmdDictionary[arguments[0]].DynamicInvoke(readString, PlayerObj);
    else
        returnTuple = doHuh(readString, PlayerObj);
    return returnTuple;
}

問題は、次のエラー メッセージが表示されることです。

cmdDictionary.Add(playerCommand.CommandName, new Func<string, Player, Tuple<string, Player>>(playerCommand.CommandTuple));
'GWOService.Command.CommandTuple' is a 'property' but is used like a 'method'

playerCommand.CommandName は、「doSay」または「doHuh」またはタプルの名前が何であれ、文字列ですが、次のように機能します。

cmdDictionary.Add(playerCommand.CommandName, new Func<string, Player, Tuple<string, Player>>(doSay/*playerCommand.CommandTuple*/));

アップデート

そこで、次の方法で再試行しました。

public Tuple<string, Player> handleCMD(string readString, Player PlayerObj)
{
    Tuple<string, Player> returnTuple = new Tuple<string, Player>(readString, PlayerObj);
    string[] arguments = readString.Split(' ');
    DBHandler dbHandler = new DBHandler();
    Dictionary<string, Delegate> cmdDictionary = new Dictionary<string, Delegate>();
    foreach (Command playerCommand in dbHandler.GetCommands())
    {
        try
        {
            MethodInfo method = GetType().GetMethod(playerCommand.CommandTuple);
            //Func<string, Player, Tuple<string, Player>> func = ( ) => { return (Tuple<string, Player>)(this.GetType().GetMethod(playerCommand.CommandTuple).Invoke(this, new object[0])); }
            Func<string, Player, Tuple<string, Player>> func = (Func<string, Player, Tuple<string, Player>>)Delegate.CreateDelegate(typeof(Func<string, Player, Tuple<string, Player>>), method);
            cmdDictionary.Add(playerCommand.CommandName, new Func<string, Player, Tuple<string, Player>>(func));
        }
        catch (Exception e)
        {
            dbHandler.LogEntry(PlayerObj, e.ToString());
        }
    }
    if (cmdDictionary[arguments[0]] != null)
        returnTuple = (Tuple<string, Player>)cmdDictionary[arguments[0]].DynamicInvoke(readString, PlayerObj);
    else
        returnTuple = doHuh(readString, PlayerObj);

    //switch (arguments[0].ToLower())
    //{
    //    case "addchange":
    //        returnTuple = doAddChange(readString, PlayerObj);
    //        break;
    //    case "changes":
    //        returnTuple = doChanges(readString, PlayerObj);
    //        break;
    //    case "score":
    //        returnTuple = doScore(readString, PlayerObj);
    //        break;
    //    case "look":
    //        returnTuple = doLook(readString, PlayerObj);
    //        break;
    //    case "north":
    //        returnTuple = doWalk(arguments[0], PlayerObj);
    //        break;
    //    case "east":
    //        returnTuple = doWalk(arguments[0], PlayerObj);
    //        break;
    //    case "south":
    //        returnTuple = doWalk(arguments[0], PlayerObj);
    //        break;
    //    case "west":
    //        returnTuple = doWalk(arguments[0], PlayerObj);
    //        break;
    //    case "quit":
    //        returnTuple = doQuit(readString, PlayerObj);
    //        break;
    //    case "chat":
    //        returnTuple = doChat(readString, PlayerObj);
    //        break;
    //    case "say":
    //        returnTuple = doSay(readString, PlayerObj);
    //        break;
    //    case "who":
    //        returnTuple = doWho(readString, PlayerObj);
    //        break;
    //    case "tell":
    //        returnTuple = doTell(readString, PlayerObj);
    //        break;
    //    default:
    //        returnTuple = doHuh(readString, PlayerObj);
    //        break;
    //}
    return returnTuple;
}

しかし、私はエラーが発生しています:

25行目

Func<string, Player, Tuple<string, Player>> func = (Func<string, Player, Tuple<string, Player>>)Delegate.CreateDelegate(typeof(Func<string, Player, Tuple<string, Player>>), method);

System.ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, MethodInfo method)
at GWOService.CmdHandler.handleCMD(String readString, Player PlayerObj) in \Projects\GodWarsOxide\GWOService\CmdHandler.cs:line 25
4

2 に答える 2

2

GetMethod名前で呼び出す必要があるメソッドを取得するために使用できます

this.GetType().GetMethod("doSay")

次に、必要な引数と戻り値の型を使用して、のコマンドでFuncorを作成できます。DelegateInvokeMethodInfo

var function = new Func<string, Player, Tuple<string, Player>>((arg1, arg2) => (Tuple<string, Player>)this.GetType().GetMethod("doSay").Invoke(this, new object[] { arg1, arg2 })));

ラップして再利用できるようにする

public Func<string, Player, Tuple<string, Player>> CreateFunction(string methodName)
{
    if (this.GetType().GetMethods().Any(x => x.Name == methodName))
    {
        return new Func<string, Player, Tuple<string, Player>>((arg1, arg2) => (Tuple<string, Player>)this.GetType().GetMethod(methodName).Invoke(this, new object[] { arg1, arg2 }));
    }
    return null;
}

次に、これらをDictionary

  var functions = new Dictionary<string, Func<string, Player, Tuple<string, Player>>>();
  functions.Add("Say",CreateFunction("doSay"));

またはあなたからDatabase

foreach (Command playerCommand in dbHandler.GetCommands())
{
    if (!functions.ContainsKey(playerCommand.CommandName))
    {
        functions.Add(playerCommand.CommandName, CreateFunction(playerCommand.CommandTuple));
    }
}

そして、いつでもそれらを呼び出すことができます

 var result = functions["Say"]("Hello", new Player());

ノート:

Tuple<sting, Player>アプリケーション全体で処理するのが楽になるので、代わりに以下のような素敵なクラスに置き換えることをお勧めします

public void Test()
{
    Dictionary<string, Func<string, Player, MyResult>> functions = new Dictionary<string, Func<string, Player, MyResult>>();
    functions.Add("Say",CreateFunction("doSay"));
    var result = functions["Say"]("Hello", new Player());
}

public Func<string, Player, MyResult> CreateFunction(string methodName)
{
    if (this.GetType().GetMethods().Any(x => x.Name == methodName))
    {
        return new Func<string, Player, MyResult>((arg1, arg2) => (MyResult)this.GetType().GetMethod(methodName).Invoke(this, new object[] { arg1, arg2 }));
    }
    return null;
}

public MyResult doSay(string value1, Player value2)
{
    return new MyResult(value1, value2);
}

public class MyResult
{
    public MyResult(string value1, Player value2)
    {
        Value1 = value1;
        Value2 = value2;
    }
    public string Value1 { get; set; }
    public Player Value2 { get; set; }
}
于 2013-09-16T22:31:06.377 に答える