仕事が忙しかったのでほったらかしになっていました。不定期で気が向いたときにだらだら更新したいと思います。
最近いじっているのがJson.NETなのでそれについて書いていこうかなと思った次第です。

Json.NET - Newtonsoft

これを使用してJsonシリアライズを行う場合。

using System;
using System.IO;
using Newtonsoft.Json;

public class LogEntry
{
    public int ID { get; set; }
    public string Details { get; set; }
    public DateTime LogDate { get; set; }
}

namespace ConsoleApplication1
{
    class Program
    {
        static void Main( string[ ] args )
        {
          LogEntry entry = new LogEntry
          {
            ID      = 0,
            LogDate = new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc),
            Details = "Application started."
          };
          // 文字列の場合
          string jsonString = JsonConvert.SerializeObject( entry );

          // ファイル書き出しの場合
          JsonSerializer serializer = new JsonSerializer( );
          using( StreamWriter sw = new StreamWriter( @".\json.txt" ) )
          using( JsonWriter writer = new JsonTextWriter( sw ) )
          {
                serializer.Serialize( writer, entry );
          }
        }
    }
}
// Result:
// {"ID":0,"Details":"Application started.","LogDate":"\/Date(1234656000000)\/"}

とプロパティをJson形式で吐き出してくれる。
プロパティを吐き出したくないのがある。そのようなときは

[JsonObject(MemberSerialization.OptIn)]
public class LogEntry
{
    public int ID { get; set; }
    public string Details { get; set; }
    public DateTime LogDate { get; set; }
}
// 下は変わらないので省略
// Result:
// {}

となりプロパティが吐き出されるのを抑制できる。
特定のプロパティだけ吐き出す場合は、

[JsonObject( MemberSerialization.OptIn )]
public class LogEntry
{
    // これでプロパティを吐き出せるようになる
    [JsonProperty]
    public int ID { get; set; }
    // 特定のプロパティ名をつけることも可能
    [JsonProperty("details!!!!!")]
    public string Details { get; set; }
    // あえて何もつけない
    public DateTime LogDate { get; set; }
}
// Result:
// {"ID":0,"details!!!!!":"Application started."}

クラスにJsonObject( MemberSerialization.OptIn )アトリビュートを付与し、
JsonPropertyアトリビュートを各プロパティに付与するだけで簡単にシリアライズしてくれます。
逆にここだけシリアライズしたくないけれども全部にJsonPropertyつけたくないよ!というときは

public class LogEntry
{
    public int ID { get; set; }
    [JsonProperty("details!!!!!")]
    public string Details { get; set; }
    //これは変えてくれるな
    [JsonIgnore]
    public DateTime LogDate { get; set; }
}
// Result
// {"ID":0,"details!!!!!":"Application started."}

特定のプロパティにのみJsonIgnoreアトリビュートを付与することでそこだけ抑制することも可能です。

データ量的にXMLより軽いのでJsonをこの際使いこなせたら、と思っています。
Twitterなんかで受け取るデータなんかもxml,json,rss,atomが指定できるので受信データが少ない分高速化が期待できそうです。
ではまた次回、気が向いたら

LuaInterfaceその4

しばらく入院していました。
今回はテーブルにある関数をコールしてみます。

    public void TestLua(int a, int b)
    {
        Console.WriteLine( "function call{0}", a+b);
    }

    public void OnTick()
    {
            try
            {
                LuaObject lua;
                const string className = "test";
                LuaFunction func = lua.LoadFile( className + ".lua" );
                func.Call( );
                LuaTable Table = lua.GetTable( className );
                ( ( LuaFunction )Table[ "OnTick" ] ).Call( this );
            }
            catch( Exception e )
            {
                Console.WriteLine( e.Message );
            }
    }

test.lua

test = {

OnTick = function()
	TestLua(1,2)
end

}

LuaInterfaceその3

今回はLua上で作成した関数をコールして見ます。
Lua上の関数をコールするために一度DoFileなどで走らせることで、LuaObjectに登録することができます。

    public void OnTick()
    {
        LuaObject lua;
        lua.DoFile("test.lua");                                    //一度実行
        LuaFunction func = lua.GetFunction( "OnTick" );       
        Console.WriteLine( ( String )( ( func.Call( ) )[ 0 ] ) ); //0番目の戻り値を文字列として出力してみる
    }

test.lua

    function OnTick()
        return "OnTick"
    end

グローバル空間で計算などをしている場合は実行されてしまうので考慮して構成しないといけないのに注意。

LuaInterfaceその2

ヘルプ作成

前回アトリビュートにデスクリプションを記述したものを取得し、ファンクションの説明を出力できるようにしてみます。

     /// <summary>
    /// Lua登録ファンクションのデスクリプション作成
    /// </summary>
    class LuaFuncDescriptor
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="funcName">ファンクション名</param>
        /// <param name="funcDoc">ファンクションに対するドキュメント</param>
        /// <param name="_params">型とパラメータ名のペアのリスト</param>
        public LuaFuncDescriptor( String funcName, String funcDoc, List<Pair<String, String>> _params)
        {
            m_FunctionName = funcName;
            m_FunctionDoc = funcDoc;
            m_FunctionParameters = _params;

            String funcHeader = funcName + "(%params%) - " + funcDoc;
            String funcBody = "\n\n";
            String funcParams = "";

            Boolean bFirst = true;

            for( int i = 0; i < _params.Count; i++ )
            {
                if( !bFirst )
                    funcParams += ", ";

                funcParams += _params[ i ].First;
                funcBody += "\t" + _params[ i ].First + "\t\t" + _params[ i ].Second + "\n";

                bFirst = false;
            }
            funcBody = funcBody.Substring( 0, funcBody.Length - 1 );
            if( bFirst )
                funcBody = funcBody.Substring( 0, funcBody.Length - 1 );

            m_FunctionDocString = funcHeader.Replace( "%params%", funcParams ) + funcBody;

//            Console.WriteLine( m_FunctionDocString );

        }
        public String FuncName { get { return this.m_FunctionName; } }
        public String FuncDoc { get { return this.m_FunctionDoc; } }
        public List<Pair<String, String>> FuncParams { get { return this.m_FunctionParameters; } }
        public String FuncHeader( )
        {
            if( m_FunctionDocString.IndexOf( "\n" ) == -1 )
                return m_FunctionDocString;

            return m_FunctionDocString.Substring( 0, m_FunctionDocString.IndexOf( "\n" ) );
        }

        private String m_FunctionName;
        private String m_FunctionDoc;
        private List<Pair<String, String>> m_FunctionParameters = null;
        private String m_FunctionDocString;    
    }
    /// <summary>
    /// 一般的なペア
    /// </summary>
    /// <typeparam name="F"></typeparam>
    /// <typeparam name="S"></typeparam>
    class Pair<F, S>
    {
        public F First { get; set; }
        public S Second{ get; set; }
        public Pair( F first, S second )
        {
            First = first;
            Second = second;
        }
    }

これでファンクションについてのデスクリプションがつくられました。これを前回のLuaObjectクラスに組み込み、

    using YS = Yanesdk.Script;

    class LuaObject : YS.Lua
    {
        public LuaObject( )
        {
            m_LuaFuncs = new Hashtable( );
        }

        /// <summary>
        /// オブジェクト内に存在するファンクションアトリビュートを登録
        /// </summary>
        /// <param name="target"></param>
        public void RegisterObjectFunctions( Object target )
        {
            Type targetType = target.GetType( );

            foreach( MethodInfo mInfo in targetType.GetMethods( ) )
            {
                foreach( Attribute attr in Attribute.GetCustomAttributes( mInfo ) )
                {
                    if( attr.GetType( ) == typeof( AttrLuaFunc ) )
                    {
                        AttrLuaFunc attrFunc = ( AttrLuaFunc )attr;
                        List<Pair<String, String>> _params = new List<Pair<String, String>>( );

                        String funcName = attrFunc.FuncName;
                        String funcDoc = attrFunc.FuncDoc;
                        String[ ] paramDocs = attrFunc.FuncParams;

                        ParameterInfo[ ] prmInfo = mInfo.GetParameters( );

                        if( paramDocs != null && ( prmInfo.Length != paramDocs.Length ) )
                        {
                            Console.WriteLine( "Function " + mInfo.Name + " (exported as " +
                                              funcName + ") argument number mismatch. Declared " +
                                              paramDocs.Length + " but requires " +
                                              prmInfo.Length + "." );
                            break;
                        }

                        for( int i = 0; i < prmInfo.Length; i++ )
                        {
                            _params.Add( new Pair<String, String>(prmInfo[ i ].ParameterType.ToString(), paramDocs[ i ] ));
                        }

                        LuaFuncDescriptor desc = new LuaFuncDescriptor( funcName, funcDoc, _params );

                        m_LuaFuncs.Add( funcName, desc );

                        RegisterFunction( funcName, target, mInfo );
                    }
                }
            }
        }
        private Hashtable m_LuaFuncs = null;
    }

これをあとはLua側から呼べるようにしたり、外部に出力なりすればよろしいのかな。

LuaInterfaceその1

環境構築

手っ取り早く環境を整えたかったのでYaneuraoGameSDK.NETを使用して構築しました。
Lua.NET for Yanesdk.NETとScintilla and SciTEをインストールしました。

Functionの登録

関数の登録をするためにアトリビュートを使用して

    /// <summary>
    /// Luaへ関数を登録するためのアトリビュート
    /// </summary>
    class AttrLuaFunc : Attribute
    {
        /// <summary>
        /// 関数の登録
        /// </summary>
        /// <param name="funcName">登録する関数名</param>
        /// <param name="funcDoc">登録した関数の説明</param>
        public AttrLuaFunc( String funcName, String funcDoc )
        {
            m_FunctionName = funcName;
            m_FunctionDoc = funcDoc;
        }
        /// <summary>
        /// 引数付き関数の登録
        /// </summary>
        /// <param name="funcName">登録する関数名</param>
        /// <param name="funcDoc">登録した関数の説明</param>
        /// <param name="paramDocs">登録した関数の引数の説明</param>
        public AttrLuaFunc( String funcName, String funcDoc, params String[] paramDocs)
        {
            m_FunctionName = funcName;
            m_FunctionDoc = funcDoc;
            m_FunctionParameters = paramDocs;
        }
        public String   FuncName { get { return this.m_FunctionName; } }
        public String   FuncDoc { get { return this.m_FunctionDoc; } }
        public String[ ] FuncParams { get { return this.m_FunctionParameters; } }

        private String m_FunctionName;
        private String m_FunctionDoc;
        private String[ ] m_FunctionParameters = null;
    }

こんな感じに実装してみました。

それで、

    /// <summary>
    /// Luaオブジェクト管理
    /// </summary>
    class LuaObject : YS.Lua
    {
        public LuaObject( )
        {
            m_LuaFuncs = new Hashtable( );
        }

        public void RegisterLuaFunctions( Object target )
        {
            Type targetType = target.GetType( );

            foreach( MethodInfo mInfo in targetType.GetMethods( ) )
            {
                foreach( Attribute attr in Attribute.GetCustomAttributes( mInfo ) )
                {
                    if( attr.GetType( ) == typeof( AttrLuaFunc ) )
                    {
                        AttrLuaFunc attrFunc = ( AttrLuaFunc )attr;

                        String funcName = attrFunc.FuncName;

                        ParameterInfo[ ] prmInfo = mInfo.GetParameters( );

                        m_LuaFuncs.Add( funcName, desc );

                        RegisterFunction( funcName, target, mInfo );
                    }
                }
            }
        }
        private Hashtable m_LuaFuncs = null;
    }

これでクラスが持っている登録すべき関数を一挙に登録できるわけです。
これで関数のヘルプが外部から見れるようにできれば、というのは次回やりたいと思います。