【问题标题】:C# RPC expose API methodsC# RPC 公开 API 方法
【发布时间】:2017-01-20 02:02:16
【问题描述】:

好的,到目前为止,我有一种方法可以使用它来公开一些方法:

AddCommand ("UpdateStar", ((args) => {
   // do something
}));

它将命令添加到SortedDictionary<string, SimpleDelegate>。 这是我的SimpleDelegate 定义:

public delegate void SimpleDelegate(JSONNode args);

这很简单,我从 Javascript 发送一个参数列表,在 C# 中我收到一个 JSONNode,它是一个 JSONArray。它正在工作,但做一些事情很烦人,例如:

string name = args[0].Value;
int x = args[1].AsInt;
...

最后,我想做的是在 C# 中公开实际方法,而不是公开 lambda。

换句话说,我想做这样的事情:

[expose-to-rpc]
public void AddSystem(string name, int x, int y) {

}

它可以使用反射找到方法的名称、参数的数量和参数的类型。我很确定这样的事情是可能的,但我有点迷失在这里。不知道如何开始。

【问题讨论】:

标签: c# unity3d reflection mono


【解决方案1】:

啊,我明白了。这比我想象的要容易......

首先,这个类是必需的:

[AttributeUsage(AttributeTargets.Method)]
public class ExposeAttribute: Attribute {
}

然后我们需要添加这个其他类:

public static class RPCApi
{

    public static object nodeToType(JSONNode node, Type type) {
        if (typeof(int) == type) {
            return node.AsInt;
        }
        if (typeof(long) == type) {
            return node.AsLong;
        }
        if (typeof(bool) == type) {
            return node.AsBool;
        }
        if (typeof(string) == type) {
            return node.Value;
        }
        if (typeof(float) == type) {
            return node.AsFloat;
        }
        if (typeof(double) == type) {
            return node.AsDouble;
        }
        if (typeof(JSONArray) == type) {
            return node.AsArray;
        }
        if (typeof(JSONClass) == type) {
            return node.AsObject;
        }

        return null;
    }

    public static void Resolve(MonoBehaviour behaviour) {
        NetworkManager manager = behaviour.GetComponent<NetworkManager> ();
        Type t = behaviour.GetType ();
        MethodInfo[] methods = t.GetMethods ();

        for (int i = 0; i < methods.Length; i++) {
            MethodInfo meth = methods [i];
            ExposeAttribute[] atts = (ExposeAttribute[])meth.GetCustomAttributes (typeof(ExposeAttribute), true);

            if (atts.Length == 0) {
                continue;
            }

            ParameterInfo[] paramss = meth.GetParameters ();
            manager.AddCommand (meth.Name, ((args) => {
                object[] argss = new object[paramss.Length];
                for(int l=0; l<argss.Length; l++) {
                    argss[l] = nodeToType(
                      args[l],
                      paramss[l].ParameterType
                    );
                }
                meth.Invoke(behaviour, argss);
            }));
        }
    }
}

首先我们得到传递给Resolve的对象的所有方法。检查任何具有 Expose 属性的方法。

如果存在,查找参数类型并创建一个新命令,就像我之前所做的那样......在调用实际方法之前,我们将参数转换为方法所期望的类型。由于我们接收 JSON,我们无法接收复杂类型,因此我们可以轻松转换大多数参数......也就是说,可能有更好的方法。

最后,如何使用它:

public class NetworkManager : MonoBehaviour {

    public void Start () {
        RPCApi.Resolve (this);
    }

    ...

    [Expose]
    public void addStar(string system) {
        Planet fun = JsonUtility.FromJson<Planet> (system);
        GameObject prefabs = GameObject.Find ("PrefabContainer");
        PrefabContainer obj = prefabs.GetComponent<PrefabContainer> ();
        GameObject newobj = Instantiate (obj.star, new Vector3 (fun.x, fun.y, 0), Quaternion.Euler (0, 0, 0));
        newobj.name = fun.id;
        newobj.GetComponent<PlanetBehaviour> ().planetConfig = fun;
    }

    [Expose]
    public void UpdateStar (string uuid, float x, float y) {
        GameObject system = GameObject.Find (uuid);
        MoveToBehaviour move = system.GetComponent<MoveToBehaviour>();
        move.MoveTo(new Vector3(x, y, 0));
    }
}

添加返回类型也不应该更难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-06
    • 2010-09-21
    • 2015-05-25
    • 2022-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    相关资源
    最近更新 更多