Exemplo n.º 1
0
        ICoder <IEnumerable <ModelMeta> > GenDataAccessCoder()
        {
            Func <FieldMeta, bool> isKey = meta => meta.ModelMeta.Key == meta;
            var loadFieldMethodName      =
                "Load{0}At{1}Async".Basic <FieldMeta>(meta => meta.Name, meta => meta.ModelMeta.Name);
            var updateFieldMethodName =
                "Update{0}At{1}".Basic <FieldMeta>(meta => meta.Name, meta => meta.ModelMeta.Name);

            var fieldPara =
                "{0} {1}".Basic <FieldMeta>(meta => CoderHelper.GetTypeStr(meta.Type), meta => meta.Name.ToLower());
            var modelFieldPara =
                "{0} {1}".Basic <ModelMeta>(meta => CoderHelper.GetTypeStr(meta.Type), meta => meta.Name.ToLower());

            // Task<uint> LoadUidAtPlayerInfoAsync()
            var loadField =
                "{0} {1}()".Basic <FieldMeta>(meta => CoderHelper.TaskTypeCoder().Code(meta.Type),
                                              loadFieldMethodName.Code);

            // void UpdateUidAtPlayerInfo(uint uid)
            var updateField =
                "void {0}({1})".Basic <FieldMeta>(updateFieldMethodName.Code, meta => fieldPara.Code(meta));

            // Task<PlayerInfo> LoadPlayerInfoAsync(ulong pid)
            var loadModel =
                "{0} Load{1}Async()".Basic <FieldMeta>(meta => CoderHelper.TaskTypeCoder().Code(meta.ModelMeta.Type),
                                                       meta => meta.ModelMeta.Name);

            // void UpdatePlayerInfo(PlayerInfo info)
            var updateModel =
                "void Update{0}({1})".Basic <FieldMeta>(meta => meta.ModelMeta.Name, meta => modelFieldPara.Code(meta.ModelMeta));

            // ISessionReader
            var readInterfaceName = "I{0}Reader".Basic <ModelMeta>(meta => meta.Name);
            // ISessionAccesser
            var accessInterfaceName = "I{0}Accesser".Basic <ModelMeta>(meta => meta.Name);

            // public interface ISessionReader : IDisposable{...}
            var readInterface = "public interface {0}: IDisposable"
                                .Basic <ModelMeta>(meta => readInterfaceName.Code(meta))
                                .Combine(
                Generator.GenSelect(loadModel.Satisfy(isKey), loadField)
                .Statement()
                .Many("\n")
                .Brace()
                , meta => meta.Fields);

            // public interface ISessionAccesser : ISessionReader, ISubmitChangable{...}
            var accessInterface = "public interface {0}: {1}, ISubmitChangable"
                                  .Basic <ModelMeta>(meta => accessInterfaceName.Code(meta), meta => readInterfaceName.Code(meta))
                                  .Combine(
                Generator.GenSelect(updateModel.Satisfy(isKey), updateField)
                .Statement()
                .Many("\n")
                .Brace()
                , meta => meta.Fields);

            var modelAllFields =
                "#region {0}".Basic <ModelMeta>(meta => meta.Name)
                .SkipLine()
                .Combine(
                    Generator.GenSelect(loadModel.Satisfy(isKey), loadField)
                    .Statement()
                    .Many("\n")
                    ,
                    meta => meta.Fields)
                .Combine(
                    Generator.GenSelect(updateModel.Satisfy(isKey), updateField)
                    .Statement()
                    .Many("\n")
                    ,
                    meta => meta.Fields)
                .SkipLine()
                .WithPostfix("#endregion\n");

            // var val = new PlayerInfo();
            // var val = default(UInt);
            var val =
                Generator.GenSelect(
                    "var val = default({0});".Basic <Type>(CoderHelper.GetTypeStr).Satisfy(meta => meta.IsPrimitive || meta == typeof(string) || meta.IsArray)
                    //, "byte[] val = null;".Unit<Type>().Satisfy(meta=>meta == typeof(byte[]))
                    , "var val = new {0}();".Basic <Type>(CoderHelper.GetTypeStr));

            // default(T) / null
            var failVal =
                Generator.GenSelect(
                    "default({0})".Basic <Type>(CoderHelper.GetTypeStr).Satisfy(meta => meta.IsPrimitive || meta == typeof(string) || meta.IsEnum)
                    , "null".Unit <Type>());

            // reader.ReadField<UInt64>("Pid");/(TowerState)reader.ReadField<Int32>("Test");
            var readField =
                Generator.GenSelect(
                    "({0})reader.ReadField<Int32>(\"{1}\");".Basic <FieldMeta>(meta => CoderHelper.GetTypeStr(meta.Type), meta => meta.Name).Satisfy(meta => meta.Type.IsEnum)
                    , "reader.ReadField<{0}>(\"{1}\");".Basic <FieldMeta>(meta => CoderHelper.GetTypeStr(meta.Type), meta => meta.Name));

            // val = reader.ReadField<UInt64>("Pid");
            var fieldReadField =
                "val = {0}".Basic <FieldMeta>(readField.Code);

            // val.Pid = reader.ReadField<UInt64>("Pid");
            var modelReadField =
                "val.{0} = {1}".Basic <FieldMeta>(meta => meta.Name, readField.Code);

            // val.Pid = (ulong)key;
            var modelReadKeyField =
                "val.{0} = ({1})key;".Basic <FieldMeta>(meta => meta.Name, meta => CoderHelper.GetTypeStr(meta.Type));

            var fieldReader =
                Generator.GenSelect(
                    "".Unit <FieldMeta>()
                    .Combine(Generator.GenSelect(modelReadKeyField.Satisfy(isKey), modelReadField).Many("\n"), meta => meta.ModelMeta.Fields)
                    .Satisfy(isKey)
                    , fieldReadField);

            var fieldModelGetter =
                "(Int32)".Unit <FieldMeta>().Satisfy(meta => meta.Type.IsEnum)
                .Append("{1}.{0}".Basic <FieldMeta>(meta => meta.Name, meta => meta.ModelMeta.Name.ToLower()));

            var fieldGetter =
                "(Int32)".Unit <FieldMeta>().Satisfy(meta => meta.Type.IsEnum)
                .Append("{0}".Basic <FieldMeta>(meta => meta.Name.ToLower()));

            // .WriteField("InfoSkill", infoskill)
            var writeField =
                ".WriteField(\"{0}\", {1})".Basic <FieldMeta>(meta => meta.Name, fieldGetter.Code);

            // .WriteField("{0}", ({1})key)
            var writeKey =
                ".WriteField(\"{0}\", ({1})key)".Basic <FieldMeta>(meta => meta.Name, meta => CoderHelper.GetTypeStr(meta.Type));

            // .WriteField("Pid", playerinfo.Pid)
            var writeFieldModel =
                ".WriteField(\"{0}\", {1})".Basic <FieldMeta>(meta => meta.Name, fieldModelGetter.Code);

            Func <bool, ICoder <FieldMeta> > writer =
                isRedis =>
            {
                return("var ctx =  adaptor.Update(dataId);\n\nctx".Unit <FieldMeta>()
                       .SkipLine()
                       .Append(Generator.GenSelect(
                                   "".Unit <FieldMeta>().Combine(Generator.GenSelect(
                                                                     writeFieldModel.Satisfy(isKey), writeFieldModel).Many("\n"),
                                                                 meta => meta.ModelMeta.Fields).Satisfy(isKey)
                                   ,
                                   "{0}".Basic <FieldMeta>(meta => writeKey.Code(meta.ModelMeta.Key))
                                   .SkipLine().Satisfy(meta => !isRedis)
                                   .Append(writeField)))
                       .SkipLine()
                       .Append(
                           ";\nupdateQueue.Add(ctx);".Unit <FieldMeta>()));
            };

            var updateSig = Generator.GenSelect(updateModel.Satisfy(isKey), updateField).WithPrefix("public ");
            var loadSig   = Generator.GenSelect(loadModel.Satisfy(isKey), loadField).WithPrefix("public async ");

            #region redis

            // var dataId = string.Format("player:{0}", id);
            var key =
                "var dataId = string.Format(\"{0}:{{0}}\", {1});".Basic <FieldMeta>(
                    meta => meta.ModelMeta.RedisCacheName, meta => meta.ModelMeta.Key.Name.ToLower());

            var redisReader =
                Generator.GenSelect(
                    "var reader = await adaptor.QueryAll(dataId);if (reader == null){{return {0};}}".Basic <FieldMeta>(meta => failVal.Code(meta.ModelMeta.Type))
                    .Satisfy(isKey)
                    ,
                    "var reader = await adaptor.Query(dataId, \"{0}\");if (reader == null){{return {1};}}"
                    .Basic <FieldMeta>(meta => meta.Name, meta => failVal.Code(meta.Type)));

            var redisUpdateLast =
                "return await adaptor.UpdateWork({0});".Basic <FieldMeta>(meta => meta.ModelMeta.Key.Name.ToLower());

            var redisUpdate =
                updateSig.Append(
                    writer(true) /*.Append(redisUpdateLast)*/.Brace());

            var redisLoad =
                loadSig.Append(
                    Generator.GenSelect(
                        "{0}".Basic <FieldMeta>(meta => val.Code(meta.ModelMeta.Type)).Satisfy(isKey)
                        , "".Unit <FieldMeta>().Combine(val, meta => meta.Type)).Append(redisReader).Append(fieldReader).WithPostfix("return val;").Brace());

            var interfaceInherit =
                accessInterfaceName.Many(",");

            var delegateInnerRedisSpecial =
                @"public async Task<bool> SubmitChanges()
            {
                await adaptor.SubmitChanges(
        new[] { dataId }
      , new[] { contextLockId }
      , new [] {updateQueue});

                return true;
            }

            public async Task<bool> SubmitChangesWith(params object[] others)
            {
                await adaptor.SubmitChanges(
                    new[] { dataId } .Concat(others.Select(d => ((DelegateBase)d).dataId)).ToArray(),
                    new[] { contextLockId } .Concat(others.Select(d => ((DelegateBase)d).contextLockId)).ToArray(),
                    new[] { updateQueue } .Concat(others.Select(d => ((DelegateBase)d).updateQueue)).ToArray());

                return true;
            }

            public void Dispose()
            {

            }
".Unit();

            var redisDelegateInner =
                @"class Delegate<TKey> : DelegateBase, {0}
{{            
public Delegate(RedisAdaptor adaptor, long contextLockId, TKey key, string dataId)
            {{
                this.adaptor = adaptor;
                this.contextLockId = contextLockId;
                this.key = key;
                this.dataId = dataId;
            }}
            {2}
            private readonly RedisAdaptor adaptor;
            private readonly object key;

            {1}
}}"
                .Basic <IEnumerable <ModelMeta> >(
                    interfaceInherit.Code,
                    "#region {0}\n{1}\n#endregion\n".Basic <ModelMeta>(meta => meta.Name,
                                                                       meta => redisUpdate.Many("\n").SkipLine().Append(redisLoad.Many("\n")).Code(meta.Fields)).Many("\n").Code, delegateInnerRedisSpecial.Code);

            var modelReaderGetter =
                "public async Task<I{0}Reader> Get{0}Reader({1} {2}){{var dataId = string.Format(\"{3}:{{0}}\", {2});var lockId = 0;return new Delegate<{1}>(adaptor, lockId, {2}, dataId);}}"
                .Basic <ModelMeta>(
                    meta => meta.Name
                    , meta => CoderHelper.GetTypeStr(meta.Key.Type)
                    , meta => meta.Key.Name.ToLower()
                    , meta => meta.Name.ToLower());
            var modelAccesserGetter =
                "public async Task<I{0}Accesser> Get{0}Accesser({1} {2}){{var dataId = string.Format(\"{3}:{{0}}\", {2});var lockId = await adaptor.LockKey(dataId);return new Delegate<{1}>(adaptor, lockId, {2}, dataId);}}"
                .Basic <ModelMeta>(
                    meta => meta.Name
                    , meta => CoderHelper.GetTypeStr(meta.Key.Type)
                    , meta => meta.Key.Name.ToLower()
                    , meta => meta.Name.ToLower());

            var redisDelegate = "public class RedisDataServiceDelegate {{\n{0}\n{1}\n\nprivate readonly RedisAdaptor adaptor;public RedisDataServiceDelegate(RedisAdaptor adaptor){{this.adaptor = adaptor;}}\n }}"
                                .Basic <IEnumerable <ModelMeta> >(
                redisDelegateInner.Code
                , modelReaderGetter.SkipLine().Append(modelAccesserGetter).Many("\n").Code);

            #endregion

            #region mysql

            // `Pid`, `Uid`, `Name`, `Level`, `InfoSkill` ,`InfoItem`
            var fields =
                Generator.GenSelect(
                    "".Unit <FieldMeta>()
                    .Combine("`{0}`".Basic <FieldMeta>(meta => meta.Name).Many(","),
                             meta => meta.ModelMeta.Fields)
                    .Satisfy(meta => meta.ModelMeta.Key == meta)
                    , "`{0}`".Basic <FieldMeta>(meta => meta.Name));

            // const string sql = "SELECT `Pid`, `Uid`, `Name`, `Level`, `InfoSkill` ,`InfoItem` FROM `mem_player` WHERE `Pid` = ?1";
            var querySql =
                "const string sql = \"SELECT {0} FROM `{1}` WHERE `{2}` = ?1\";"
                .Basic <FieldMeta>(fields.Code, meta => meta.ModelMeta.MysqlTableName,
                                   meta => meta.ModelMeta.Key.Name);

            var mysqlReader =
                Generator.GenSelect(
                    "var reader = await adaptor.Query(sql, ({0})key);if (reader == null){{return {1};}}"
                    .Basic <FieldMeta>(meta => CoderHelper.GetTypeStr(meta.ModelMeta.Key.Type), meta => failVal.Code(meta.ModelMeta.Type))
                    .Satisfy(isKey)
                    ,
                    "var reader = await adaptor.Query(sql, ({0})key);if (reader == null){{return {1};}}"
                    .Basic <FieldMeta>(meta => CoderHelper.GetTypeStr(meta.ModelMeta.Key.Type), meta => failVal.Code(meta.Type)));

            var updateSqlKeyString =
                "INSERT INTO `{0}`({1}) VALUES({2}) ON DUPLICATE KEY UPDATE {3}".Basic <FieldMeta>(
                    meta => meta.ModelMeta.MysqlTableName
                    ,
                    "".Unit <FieldMeta>()
                    .Combine("`{0}`".Basic <FieldMeta>(meta => meta.Name).Many(","),
                             meta => meta.ModelMeta.Fields)
                    .Code
                    ,
                    "".Unit <FieldMeta>()
                    .Combine("?{0}".Basic <FieldMeta>(meta => meta.Position).Many(","),
                             meta => meta.ModelMeta.Fields)
                    .Code
                    ,
                    "".Unit <FieldMeta>()
                    .Combine(
                        "`{0}`=?{1}".Basic <FieldMeta>(meta => meta.Name, meta => meta.Position)
                        .Many(",", meta => !isKey(meta)), meta => meta.ModelMeta.Fields)
                    .Code);

            var updateSqlFieldString =
                "UPDATE `{0}` SET `{1}`=?2 WHERE `{2}`=?1".Basic <FieldMeta>(
                    meta => meta.ModelMeta.MysqlTableName, meta => meta.Name, meta => meta.ModelMeta.Key.Name);

            var updateSql =
                "const string dataId = \"{0}\"; ".Basic <FieldMeta>(Generator.GenSelect(
                                                                        updateSqlKeyString.Satisfy(isKey), updateSqlFieldString).Code);

            var mysqlUpdate =
                updateSig.Append(
                    Generator.GenSelect(
                        updateSql.Append(writer(false)).Satisfy(meta => meta.ModelMeta.MysqlTableName != null)
                        , "throw new Exception();".Unit <FieldMeta>())
                    .Brace());

            var mysqlLoad =
                loadSig.Append(
                    Generator.GenSelect(
                        querySql.Append(Generator.GenSelect(
                                            "{0}".Basic <FieldMeta>(meta => val.Code(meta.ModelMeta.Type)).Satisfy(isKey)
                                            , "".Unit <FieldMeta>().Combine(val, meta => meta.Type))).Append(mysqlReader).Append(fieldReader).WithPostfix("reader.Dispose();\nreturn val;").Satisfy(meta => meta.ModelMeta.MysqlTableName != null)
                        , "throw new Exception();".Unit <FieldMeta>())
                    .Brace());
            var delegateInnerMysqlSpecial =
                @"            public Task<bool> SubmitChanges()
            {
            throw new NotImplementedException();
            }

            public Task<bool> SubmitChangesWith(params object[] others)
            {
            throw new NotImplementedException();
            }

            public void Dispose()
            {

            }
".Unit();

            var mysqlDelegateInner =
                @"class Delegate<TKey> : {0}
{{            
public Delegate(MysqlAdaptor adaptor, TKey key)
            {{
                this.adaptor = adaptor;
                this.key = key;
            }}
            {2}
            private readonly MysqlAdaptor adaptor;
            private readonly object key;
            private readonly List<IUpdateDataContext> updateQueue = new List<IUpdateDataContext>();

            {1}
}}"
                .Basic <IEnumerable <ModelMeta> >(
                    accessInterfaceName.Many(",", m => m.MysqlTableName != null).Code,
                    "#region {0}\n{1}\n#endregion\n".Basic <ModelMeta>(meta => meta.Name,
                                                                       meta => mysqlUpdate.Many("\n").SkipLine().Append(mysqlLoad.Many("\n")).Code(meta.Fields)).Many("\n", m => m.MysqlTableName != null).Code, delegateInnerMysqlSpecial.Code);

            Func <string, ICoder <ModelMeta> > mysqlModelGetter = interfaceType =>
            {
                return(string.Format("public async Task<I{{0}}{0}> Get{{0}}{0}({{1}} {{2}}){{{{return new Delegate<{{1}}>(adaptor, {{2}});}}}}"
                                     , interfaceType)
                       .Basic <ModelMeta>(
                           meta => meta.Name
                           , meta => CoderHelper.GetTypeStr(meta.Key.Type)
                           , meta => meta.Key.Name.ToLower()
                           , meta => meta.Name.ToLower()));
            };

            var mysqlModelReaderGetter   = mysqlModelGetter("Reader");
            var mysqlModelAccesserGetter = mysqlModelGetter("Accesser");

            var mysqlDelegate = "public class MysqlDataServiceDelegate {{{0}\n{1}\n\nprivate readonly MysqlAdaptor adaptor;public MysqlDataServiceDelegate(MysqlAdaptor adaptor){{this.adaptor = adaptor;}}\n }}"
                                .Basic <IEnumerable <ModelMeta> >(
                mysqlDelegateInner.Code
                , mysqlModelReaderGetter.SkipLine().Append(mysqlModelAccesserGetter).Many("\n", m => m.MysqlTableName != null).Code);
            #endregion

            var genCoder =
                readInterface.SkipLine().Append(accessInterface).Many("\n")
                .SkipLine(2)
                .Append(redisDelegate)
                .SkipLine(2)
                .Append(mysqlDelegate);

            return(genCoder);
        }
Exemplo n.º 2
0
        ICoder <IEnumerable <ModelMeta> > GenSerializeCoder(bool isClient)
        {
            // [FieldIndex(Index = 1)]
            // public UInt32 TowerId;
            var fieldDec =
                "[FieldIndex(Index = {0})]".Basic <FieldMeta>(meta => meta.SerializeIndex)
                .Satisfy(meta => meta.SerializeIndex > 0 && !isClient)
                .SkipLine()
                .Append("public {0} {1};".Basic <FieldMeta>(meta => CoderHelper.GetTypeStr(meta.Field.FieldType),
                                                            meta => meta.Field.Name))
                .Satisfy(meta => !meta.IsInherit);

            var fieldWriterWithCheck =
                CoderHelper.WriteWithCheckCoder <FieldMeta>()
                .Lift(
                    (FieldMeta meta) =>
                    new Tuple <Type, ICoder <FieldMeta>, FieldMeta>(meta.Type, "{0}".Basic <FieldMeta>(f => f.Name),
                                                                    meta));

            var writer =
                Generator.GenSelect(
                    "public void Write(BinaryWriter bw)".Unit <ModelMeta>()
                    .Combine(fieldWriterWithCheck.Many("\n").Brace(), meta => meta.Fields)
                    .Satisfy(meta => !meta.IsHierarchy)
                    ,
                    "public {0} void Write(BinaryWriter bw)".Basic <ModelMeta>(meta =>
                                                                               Generator.GenSelect(
                                                                                   "override".Unit <ModelMeta>().Satisfy(meta1 => !meta1.IsTopmostBase)
                                                                                   , "virtual".Unit <ModelMeta>()).Code(meta))
                    .Append(
                        "bw.Write((byte){0});".Basic <ModelMeta>(meta => meta.HierarchyCode)
                        .Combine(fieldWriterWithCheck.Many("\n"), meta => meta.Fields)
                        .Brace()));

            var fieldReaderWithCheck =
                CoderHelper.ReadWithCheckCoder <FieldMeta>()
                .Lift(
                    (FieldMeta meta) =>
                    new Tuple <Type, ICoder <FieldMeta>, FieldMeta>(meta.Type, "{0}".Basic <FieldMeta>(f => f.Name),
                                                                    meta));

            var reader =
                Generator.GenSelect(
                    "public {0} Read(BinaryReader br)".Basic <ModelMeta>(meta => CoderHelper.GetTypeStr(meta.Type)).Satisfy(meta => !meta.IsHierarchy)
                    , "public new {0} ReadImpl(BinaryReader br)".Basic <ModelMeta>(meta => CoderHelper.GetTypeStr(meta.Type)))
                .Combine(fieldReaderWithCheck.Many("\n").Append("return this;".Unit <IEnumerable <FieldMeta> >()).Brace(), meta => meta.Fields);

            var hierarchyReader =
                "public new {0} Read(BinaryReader br){{return ({0})ReadStatic(br);}}".Basic <ModelMeta>(
                    meta => CoderHelper.GetTypeStr(meta.Type)).Satisfy(meta => meta.IsHierarchy);

            var topmostReaderDispatcher =
                "public static {0} ReadStatic(BinaryReader br)".Basic <ModelMeta>(
                    meta => CoderHelper.GetTypeStr(meta.Type))
                .Append(
                    "byte tp = br.ReadByte();if (tp != (byte)SerializeObjectMark.IsNull){{switch (tp){{{0}{1}}}}}return null;"
                    .Basic <ModelMeta>(meta => "case {0}: return (new {1}()).ReadImpl(br);".Basic <ModelMeta>(
                                           metac => metac.HierarchyCode, metac => CoderHelper.GetTypeStr(metac.Type))
                                       .Many("\n")
                                       .Code(meta.Children), meta => "default: return (new {0}()).ReadImpl(br);".Basic <ModelMeta>(metai => CoderHelper.GetTypeStr(metai.Type)).Code(meta)).Brace());

            var dumpAtomic =
                Generator.GenSelect(
                    "{0}!=null?string.Join(\", \", Array.ConvertAll({0}, input => input.ToString())):\"null\"".Basic <FieldMeta>(
                        meta => meta.Field.Name).Satisfy(meta => meta.Field.FieldType.IsArray)
                    ,
                    "{0}!=null?string.Join(\", \", Array.ConvertAll({0}.ToArray(), input => input.ToString())):\"null\"".Basic <FieldMeta>(
                        meta => meta.Field.Name).Satisfy(meta => meta.Field.FieldType.Name.Equals("List`1"))
                    ,
                    "{0}".Basic <FieldMeta>(meta => meta.Field.Name));

            var dumpHelpAtomic = "{0}={{{1}}}\\n".Basic <FieldMeta>(meta => meta.Field.Name, meta => meta.Position - 1);

            var dump =
                "public override string ToString(){{return string.Format(\"{0}:\\n{1}\", {2});}}"
                .Basic <ModelMeta>(meta => meta.Type.Name, meta => dumpHelpAtomic.Many("").Code(meta.Fields),
                                   meta => dumpAtomic.Many(",").Code(meta.Fields));

            var serialize =
                "public class {0}{1}{{".Basic <ModelMeta>(meta => meta.Type.Name, meta => ":{0}".Basic <ModelMeta>(meta1 => CoderHelper.GetTypeStr(meta1.Parent.Type)).Satisfy(meta1 => meta1.Parent != null).Code(meta))
                .Combine(fieldDec.Many("\n"), meta => meta.Fields)
                .Append(writer.SkipLine())
                .Append(reader.SkipLine())
                .Append(hierarchyReader.SkipLine().Satisfy(meta => meta.IsHierarchy))
                .Append(topmostReaderDispatcher.SkipLine().Satisfy(meta => meta.IsTopmostBase))
                .Append(dump.SkipLine())
                .WithPostfix("}");

            return(serialize.Many("\n"));
            //return "".Unit<TypeMeta>().Combine(dumpAtomic.Many(","), meta => meta.Fields).Many("\n");
        }
        static ICoder <IEnumerable <ServiceMeta> > GenCoder(bool client)
        {
            #region name related
            // DbSyncNotify/LogicClient
            var serviceName = Generator.GenSelect(
                "{0}Notify".Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Type == ServiceType.Notify)
                , "{0}".Basic <ServiceMeta>(meta => meta.Name));

            // IDbSyncNotifyImpl
            var implName =
                "I{0}Impl".Basic <ServiceMeta>(meta => serviceName.Code(meta));

            // ILogicClientInvoke
            var invokeName =
                "I{0}Invoke".Basic <ServiceMeta>(meta => serviceName.Code(meta));

            // IClientLogicService
            var trivialServiceName =
                "I{0}Service".Basic <ServiceMeta>(meta => serviceName.Code(meta));

            // DbSyncNotifyDelegate/LoginNotifyDelegate
            var delegateName =
                Generator.GenSelect(
                    "{0}NotifyDelegate".Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Type == ServiceType.Notify)
                    , "{0}ServiceDelegate".Basic <ServiceMeta>(meta => meta.Name));

            // LoginNotifySerializer
            var serializerName =
                "{0}Serializer".Basic <ServiceMeta>(meta => serviceName.Code(meta));

            // LoginClientDispatcher
            var dispatcherName =
                "{0}Dispatcher".Basic <ServiceMeta>(meta => serviceName.Code(meta));

            // Task/Task<bool>
            var taskTypeName = Generator.GenSelect(
                "Task"
                .Unit <Type>()
                .Satisfy(meta => meta.Name.ToLower().Equals("void")),
                "Task<{0}>"
                .Basic <Type>(CoderHelper.GetTypeStr));

            // InvokeOperation/InvokeOperation<bool>
            var invokeTypeName = Generator.GenSelect(
                "InvokeOperation"
                .Unit <Type>()
                .Satisfy(meta => meta.Name.ToLower().Equals("void")),
                "InvokeOperation<{0}>"
                .Basic <Type>(CoderHelper.GetTypeStr));

            // InvokeOperation/InvokeOperation<bool>
            var invokeCallName = Generator.GenSelect(
                "Invoke"
                .Unit <Type>()
                .Satisfy(meta => meta.Name.ToLower().Equals("void")),
                "Invoke<{0}>"
                .Basic <Type>(CoderHelper.GetTypeStr));

            var invokeTaskCallName = Generator.GenSelect(
                "InvokeT"
                .Unit <Type>()
                .Satisfy(meta => meta.Name.ToLower().Equals("void")),
                "InvokeT<{0}>"
                .Basic <Type>(CoderHelper.GetTypeStr));
            #endregion

            #region function related
            // ulong pid
            var paraSig =
                "{0} {1}".Basic <ParameterMeta>(meta => CoderHelper.GetTypeStr(meta.Type), meta => meta.Name);
            // ulong pid, string newName
            var parasSig = Generator.GenSelect(
                paraSig.Many(",").Satisfy(meta => meta.Any())
                , "".Unit <IEnumerable <ParameterMeta> >().Satisfy(meta => !meta.Any()));

            // SyncPositionMulticast(int groupId, Int32 x, Int32 y)
            var methodMulticast = " {0}(int groupId, {1});".Basic <MethodMeta>(meta => meta.Name,
                                                                               meta => parasSig.Code(meta.Parameters));

            // AskChangeName(UInt64 pid, String newName);
            var methodWithoutReturnType = " {0}({1});".Basic <MethodMeta>(meta => meta.Name,
                                                                          meta => parasSig.Code(meta.Parameters));

            // Task<bool> AskChangeName(ulong pid, string newName);
            var taskMethod =
                methodWithoutReturnType.CombineReverse(taskTypeName, meta => meta.ReturnType);

            // bool AskChangeName(ulong pid, string newName);
            var normalMethod =
                methodWithoutReturnType.CombineReverse(Generator.GenBasic <Type>(CoderHelper.GetTypeStr), meta => meta.ReturnType);

            // InvokeOperation<bool> AskChangeName(ulong pid, string newName);
            var invokeMethod =
                methodWithoutReturnType.CombineReverse(invokeTypeName, meta => meta.ReturnType);
            #endregion

            #region interface related
            // public interface ILogicClientInvoke{...}
            var invokeGenCoder = Generator.GenCombine(invokeName.WithPrefix("public interface "),
                                                      invokeMethod.Many("\n").Brace(), meta => meta.Methods).Satisfy(meta => meta.Scope == ServiceScope.ClientToServer);

            // public interface ILoginNotifyImpl{...}
            var serverImplGenCoder =
                implName
                .WithPrefix("public interface ")
                .WithPostfix(": IRpcImplInstnce")
                .Combine(taskMethod.Many("\n").Brace(), meta => meta.Methods)
                .Satisfy(meta => meta.Scope != ServiceScope.ServerToClient);

            // public interface IClientLoginImpl{...}
            var clientImplGenCoder =
                implName
                .WithPrefix("public interface ")
                .WithPostfix(": IRpcImplInstnce")
                .Combine(normalMethod.Many("\n").Brace(), meta => meta.Methods)
                .Satisfy(meta => meta.Scope == ServiceScope.ServerToClient);

            #endregion

            #region delegate

            #region meta data
            // public const uint NotifyLogicServerWorking = 2001;
            var methodId =
                "public const uint {0} = {1};".Basic <MethodMeta>(meta => meta.Name, meta => meta.Id);

            // #region meta data ... #endregion
            var metaGenCoder = methodId.Many("\n").Brace().WithPrefix("private static class MethodId").Region("meta data");
            #endregion

            #region constructor && forward
            //private readonly ServiceDelegateStub serviceDelegateStub;
            //public ClientLogicServiceDelegate(IDataSender dataSender)
            //{
            //    serviceDelegateStub = new ServiceDelegateStub(dataSender, ClientLogicSerializer.Instance, MetaData.GetServiceRoutingRule(AutoInit.ClientLogic));
            //    dataSender.RegisterDelegate(serviceDelegateStub, AutoInit.ClientLogic);
            //}
            var delegateConstructor =
                @"private readonly ServiceDelegateStub serviceDelegateStub;
                  public {0}(IDataSender dataSender)
                  {{serviceDelegateStub = new ServiceDelegateStub(dataSender, {1}.Instance, MetaData.GetServiceRoutingRule(AutoInit.{2}));
                    dataSender.RegisterDelegate(serviceDelegateStub, AutoInit.{2});}}
"
                .Basic <ServiceMeta>(meta => delegateName.Code(meta), meta => serializerName.Code(meta), meta => meta.Name);

            //private readonly string forwardKey;
            //private ClientLoginServiceDelegate(ServiceDelegateStub serviceDelegateStub, string forwardKey)
            //{
            //    this.forwardKey = forwardKey;
            //    this.serviceDelegateStub = serviceDelegateStub;
            //}
            //public ClientLoginServiceDelegate Forward(byte[] sessionId)
            //{
            //    return new ClientLoginServiceDelegate(serviceDelegateStub, new Guid(sessionId).ToString());
            //}
            var delegateForward =
                @"private readonly byte[] forwardKey;
                  private {0}(ServiceDelegateStub serviceDelegateStub, byte[] forwardKey)
                  {{this.forwardKey = forwardKey;this.serviceDelegateStub = serviceDelegateStub;}}
                  public {0} Forward(byte[] forwardId)
                  {{return new {0}(serviceDelegateStub, forwardId);}}
"
                .Basic <ServiceMeta>(
                    meta => delegateName.Code(meta)).Satisfy(meta => meta.Scope == ServiceScope.ServerToClient);

            var forwardKey =
                Generator.GenSelect(
                    "forwardKey".Unit <ServiceMeta>().Satisfy(meta => meta.Scope == ServiceScope.ServerToClient)
                    , "null".Unit());
            #endregion

            // notify delegate

            // public void ServerMessageOk()
            var invokeMethodServerSig =
                "public {0} {1}({2})".Basic <MethodMeta>(meta =>
            {
                if (meta.ReturnType == typeof(void))
                {
                    return("void");
                }
                else
                {
                    return("Task<" + CoderHelper.GetTypeStr(meta.ReturnType) + ">");
                }
            }, meta => meta.Name,
                                                         meta => parasSig.Code(meta.Parameters));

            // public InvokeOperation<Boolean> AskLogin(UInt64 pid)
            var invokeMethodClientSig =
                "public {0} {1}({2})".Basic <MethodMeta>(meta => invokeTypeName.Code(meta.ReturnType), meta => meta.Name,
                                                         meta => parasSig.Code(meta.Parameters));

            // pid, newName
            var parasCall =
                "{0}".Basic <ParameterMeta>(meta => meta.Name).Many(",");

            var comma = Generator.GenSelect(
                ",".Unit <List <ParameterMeta> >().Satisfy(meta1 => meta1.Count > 0)
                , "".Unit <List <ParameterMeta> >().Satisfy(meta1 => meta1.Count == 0));

            // MethodId.AskChangeName, forwardKey, pid, newName
            var invokeCall =
                "MethodId.{0}, {1}{2}{3}".Basic <MethodMeta>(meta => meta.Name, meta => forwardKey.Code(meta.ServiceMeta), meta => comma.Code(meta.Parameters),
                                                             meta => parasCall.Code(meta.Parameters));

            // server to client delegate && notify delegate
            // serviceDelegateStub.Notify(MethodId.NotifyLogicServerWorking, null, districts);
            var invokeNoReturnBody = Generator.GenSelect(
                "serviceDelegateStub.Notify{0};".Basic <MethodMeta>(meta => invokeCall.Bracket().Code(meta)).Satisfy(
                    meta => meta.ServiceMeta.Type == ServiceType.Notify || meta.ServiceMeta.Type == ServiceType.Sync),
                "return serviceDelegateStub.{0}{1};".Basic <MethodMeta>(meta => invokeTaskCallName.Code(meta.ReturnType),
                                                                        meta => invokeCall.Bracket().Code(meta))
                );

            var multicastDelegate =
                "public void {0}Multicast(int groupId{1} {2})"
                .Basic <MethodMeta>(meta => meta.Name, meta => comma.Code(meta.Parameters),
                                    meta => parasSig.Code(meta.Parameters))
                .Append(
                    "serviceDelegateStub.Multicast(MethodId.{0}, groupId{1} {2});"
                    .Basic <MethodMeta>(meta => meta.Name, meta => comma.Code(meta.Parameters),
                                        meta => parasCall.Code(meta.Parameters)).Brace());

            // return serviceDelegateStub.Invoke<Boolean>(MethodId.AskAddMoney, null, pid, money);
            var invokeClientBody =
                "return serviceDelegateStub.{0}{1};".Basic <MethodMeta>(meta => invokeCallName.Code(meta.ReturnType),
                                                                        meta => invokeCall.Bracket().Code(meta));


            //public void NotifyPlayerLoaded(UInt64 pid){this.Task(methodNotifyPlayerLoaded, pid);}
            var invokeNoReturnMethodGen = Generator.GenFunction(invokeMethodServerSig, invokeNoReturnBody, Generator.Id);
            var invokeClientMethodGen   = Generator.GenFunction(invokeMethodClientSig, invokeClientBody, Generator.Id);

            var delegateMethod =
                Generator.GenSelect(
                    invokeClientMethodGen.Satisfy(
                        meta => meta.ServiceMeta.Scope == ServiceScope.ClientToServer && client)
                    , invokeNoReturnMethodGen);

            var delegateCoder =
                "public class {0}".Basic <ServiceMeta>(meta => delegateName.Code(meta))
                .Append(": {0}".Basic <ServiceMeta>(meta => invokeName.Code(meta))
                        .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && client))
                .Append(delegateConstructor.Append(delegateForward)
                        .Combine(metaGenCoder, meta => meta.Methods)
                        .Combine(delegateMethod.Many("\n"), meta => meta.Methods)
                        .Combine(multicastDelegate.Satisfy(meta => meta.ServiceMeta.Multicast && !client).Many("\n"), meta => meta.Methods).Brace());

            #endregion

            // case 1001:
            var label = "case {0}:".Basic <MethodMeta>(meta => meta.Id);

            #region dispatcher

            // (ulong)method.Args[0]
            var unboxedArg =
                "({0})(method.Args[{1}])".Basic <ParameterMeta>(meta => CoderHelper.GetTypeStr(meta.Type),
                                                                meta => meta.Position);

            // (UInt64)method.Args[0], (String)method.Args[1]
            var unboxedArgs = unboxedArg.Many(",");

            // AskChangeName((UInt64)method.Args[0], (String)method.Args[1])
            var dispatchMethod =
                "{0}".Basic <MethodMeta>(meta => meta.Name).Combine(unboxedArgs.Bracket(), meta => meta.Parameters);

            // public static readonly ClientLogicDispatcher Instance = new ClientLogicDispatcher();
            var dispatcherSingleton =
                "public static readonly {0} Instance = new {0}();"
                .Basic <ServiceMeta>(meta => dispatcherName.Code(meta));

            // (IDbSyncNotifyImpl)impl
            var implConvert =
                "({0})impl".Basic <ServiceMeta>(meta => implName.Code(meta));

            // ((IDbSyncNotifyImpl)impl).NotifyPlayerLoaded((UInt64)method.Args[0])
            var dispatchCall =
                "({0}).{1}".Basic <MethodMeta>(meta => implConvert.Code(meta.ServiceMeta),
                                               meta => dispatchMethod.Code(meta));

            //  case 4001:
            //  ((ILoginClientImpl)impl).AskLogin((string)method.Args[0], (byte[])method.Args[1]).ContinueWith(t => DoContinue(t, cont));
            //  break;
            //  case 5001:
            //  ((IClientLogicImpl)impl).ServerMessageOk();
            //  break;
            var dispatchSwitch =
                label.Append(
                    Generator.GenSelect(
                        "{0}.ContinueWith(t=>DoContinue(t, cont));".Basic <MethodMeta>(meta => dispatchCall.Code(meta)).Satisfy(meta => meta.ServiceMeta.Scope != ServiceScope.ServerToClient && meta.ServiceMeta.Type != ServiceType.Notify)
                        , "{0};".Basic <MethodMeta>(meta => dispatchCall.Code(meta))))
                .Append("break;".Unit <MethodMeta>());

            var dispatchMethodAll =
                "public void Dispatch(IRpcImplInstnce impl, RpcMethod method, ServiceImplementStub.SendResult cont)"
                .Unit <ServiceMeta>()
                .Append(
                    "switch (method.MethodId)"
                    .Unit <ServiceMeta>()
                    .Combine(
                        dispatchSwitch.Many("\n").Brace(), meta => meta.Methods)
                    .Brace());

            var dispatcherCoder =
                "public class {0} : "
                .Basic <ServiceMeta>(meta => dispatcherName.Code(meta))
                .Append("ServiceMethodDispatcherEx, ".Unit <ServiceMeta>().Satisfy(meta => !client))
                .Append("IServiceMethodDispatcher".Unit <ServiceMeta>())
                .Append(
                    dispatcherSingleton.Append(dispatchMethodAll).Brace());

            #endregion

            #region serializer

            // public static readonly ClientLogicSerializer Instance = new ClientLogicSerializer();
            var serializerSingleton =
                "public static readonly {0} Instance = new {0}();"
                .Basic <ServiceMeta>(meta => serializerName.Code(meta));

            var methodArgsGetter = "method.Args[{0}]".Basic <ParameterMeta>(meta => meta.Position);
            var argsGetter       = "args[{0}]".Basic <ParameterMeta>(meta => meta.Position, meta => CoderHelper.GetTypeStr(meta.Type));

            var readArgCheck =
                CoderHelper.ReadWithCheckCoder <ParameterMeta>()
                .Lift(
                    (ParameterMeta meta) =>
                    new Tuple <Type, ICoder <ParameterMeta>, ParameterMeta>(meta.Type, methodArgsGetter, meta));

            var writeArgCheck =
                CoderHelper.WriteWithCheckCoder <ParameterMeta>()
                .Lift(
                    (ParameterMeta meta) =>
                    new Tuple <Type, ICoder <ParameterMeta>, ParameterMeta>(meta.Type, argsGetter, meta));

            var readSwitch =
                label
                .Append(
                    "method.Args = new object[{0}];".Basic <MethodMeta>(meta => meta.Parameters.Count).Satisfy(meta => meta.Parameters.Count > 0)
                    .Combine(readArgCheck.Many("\n"), meta => meta.Parameters))
                //.Append(
                //    "method.NeedReturn = true;"
                //    .Unit<MethodMeta>()
                //    .Satisfy(meta => meta.ServiceMeta.Type == ServiceType.Service))
                .Append(
                    "break;".Unit <MethodMeta>());

            var readDispatchGen =
                "public RpcMethod Read(BinaryReader br)".Unit <ServiceMeta>()
                .Append(
                    "RpcMethod method = new RpcMethod();\nmethod.MethodId = br.ReadUInt32();\n".Unit <ServiceMeta>()
                    .Append(
                        "switch (method.MethodId)".Unit <ServiceMeta>()
                        .Combine(
                            readSwitch.Many("\n").Brace(), meta => meta.Methods))
                    .Append(
                        "return method;".Unit <ServiceMeta>()).Brace());

            var writeSwitch =
                label
                .Combine(
                    writeArgCheck.Many("\n").WithPostfix("break;").Brace(), meta => meta.Parameters);

            var writeDispatchGen =
                "public void Write(uint methodId, object[] args, BinaryWriter bw)"
                .Unit <ServiceMeta>()
                .Append(
                    "bw.Write(methodId);\n"
                    .Unit <ServiceMeta>()
                    .Append("switch (methodId)"
                            .Unit <ServiceMeta>()
                            .Combine(
                                writeSwitch.Many("\n").Brace(), meta => meta.Methods)).Brace());

            var readReturnWithCheck =
                CoderHelper.ReadWithCheckCoder <MethodMeta>()
                .Lift(
                    (MethodMeta meta) =>
                    new Tuple <Type, ICoder <MethodMeta>, MethodMeta>(meta.ReturnType, "returnVal".Unit <MethodMeta>(), meta));

            var readReturnSwitch =
                label
                .Append(readReturnWithCheck.WithPostfix("break;").Brace()).Satisfy(meta => meta.ReturnType != typeof(void));

            var readReturnDispatch =
                "public object ReadReturn(uint methodId, BinaryReader br)".Unit <ServiceMeta>()
                .Append(
                    (
                        ("var returnVal = new object();\n").Unit <ServiceMeta>()
                        .Append(
                            "switch (methodId)".Unit <ServiceMeta>()
                            .Combine(readReturnSwitch.Many("\n").Brace(), meta => meta.Methods)
                            .Satisfy(meta => meta.Methods.Any(m => m.ReturnType != typeof(void))))
                        .Append("return returnVal;".Unit <ServiceMeta>())
                        .Brace()
                    ));

            var writeValueWithCheck =
                CoderHelper.WriteWithCheckCoder <MethodMeta>()
                .Lift(
                    (MethodMeta meta) =>
                    new Tuple <Type, ICoder <MethodMeta>, MethodMeta>(meta.ReturnType, "value".Unit <MethodMeta>(), meta));

            var writeReturnSwitch =
                label
                .Append(writeValueWithCheck)
                .Append("break;".Unit <MethodMeta>())
                .Satisfy(meta => meta.ReturnType != typeof(void));

            var writeReturnDispatch =
                "public void WriteReturn(RpcMethod method, BinaryWriter bw, object value)".Unit <ServiceMeta>()
                .Append((
                            "switch (method.MethodId)".Unit <ServiceMeta>()
                            .Combine(
                                writeReturnSwitch.Many("\n").Brace(), meta => meta.Methods)).Satisfy(meta => meta.Methods.Any(m => m.ReturnType != typeof(void))).Brace());

            var serializerCoder =
                "public class {0} : IMethodSerializer".Basic <ServiceMeta>(meta => serializerName.Code(meta))
                .Append(
                    serializerSingleton
                    .Append(readDispatchGen.SkipLine())
                    .Append(writeDispatchGen.SkipLine())
                    .Append(readReturnDispatch.SkipLine())
                    .Append(writeReturnDispatch.SkipLine())
                    .Brace());
            #endregion

            #region serviceMeta

            var implMetaInit =
                @"MetaData.SetServiceId(typeof({0}), {1});
            MetaData.SetMethodSerializer(typeof({0}), {2}.Instance);
            MetaData.SetServiceMethodDispatcher(typeof({0}), {3}.Instance); "
                .Basic <ServiceMeta>(
                    meta => implName.Code(meta)
                    , meta => meta.Name
                    , meta => serializerName.Code(meta)
                    , meta => dispatcherName.Code(meta))
                .Satisfy(meta => (meta.Scope == ServiceScope.ServerToClient && client) || (meta.Scope != ServiceScope.ServerToClient && !client));

            var autoInitName =
                "internal const string {0} = \"{0}\";".Basic <ServiceMeta>(meta => meta.Name);

            var implBindingKey =
                Generator.GenSelect(
                    "ImplBindingKey = (districts, uuid) => \"padding.{0}.notify\",\n".Basic <ServiceMeta>(
                        meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Notify)
                    ,
                    "ImplBindingKey = (districts, uuid) => string.Format(\"{{0}}/{0}/sync/{{1}}\", districts, uuid),\n"
                    .Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(
                        meta => meta.Type == ServiceType.Sync && meta.Scope == ServiceScope.ServerToClient && client)
                    ,
                    Generator.GenSelect(
                        "ImplBindingKey = (districts, uuid) => string.Format(\"{{0}}.{0}.invoke\", districts),\n"
                        .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                        ,
                        "ImplBindingKey = (districts, uuid) => string.Format(\"padding.{0}.invoke\"),\n"
                        .Basic <ServiceMeta>(meta => meta.Name))
                    .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && !client)

                    ,
                    Generator.GenSelect(
                        Generator.GenSelect(
                            "ImplBindingKey = (districts, uuid) => string.Format(\"{{0}}.{0}.invoke\", districts),\n".Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                            , "ImplBindingKey = (districts, uuid) => string.Format(\"padding.{0}.invoke\", districts),\n".Basic <ServiceMeta>(meta => meta.Name)
                            ).Satisfy(meta => meta.Type == ServiceType.Service))
                    .Satisfy(meta => meta.Scope == ServiceScope.InterServer)

                    );

            var delegateRoutingKey =
                Generator.GenSelect(
                    "DelegateRoutingKey = (districts, fid) => \"padding.{0}.notify\",\n".Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Notify)
                    ,
                    "DelegateRoutingKey = (districts, uuid) => string.Format(\"{{0}}.{0}.sync.{{1}}\", districts, uuid),\n".Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Sync && meta.Scope == ServiceScope.ServerToClient && !client)
                    ,
                    Generator.GenSelect(
                        "DelegateRoutingKey = (districts, uuid) => string.Format(\"{{0}}/{0}/invoke\", districts),\n".Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                        , "DelegateRoutingKey = (districts, uuid) => string.Format(\"padding/{0}/invoke\"),\n".Basic <ServiceMeta>(meta => meta.Name))
                    .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && client)
                    , Generator.GenSelect(
                        Generator.GenSelect(
                            "DelegateRoutingKey = (districts, uuid) => string.Format(\"{{0}}.{0}.invoke\", districts),\n".Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                            , "DelegateRoutingKey = (districts, uuid) => string.Format(\"padding.{0}.invoke\", districts),\n".Basic <ServiceMeta>(meta => meta.Name)
                            ).Satisfy(meta => meta.Type == ServiceType.Service))
                    .Satisfy(meta => meta.Scope == ServiceScope.InterServer)
                    );

            var returnBindKey =
                Generator.GenSelect(
                    Generator.GenSelect(
                        "ReturnBindingKey = (districts, uuid) => string.Format(\"{{0}}/{0}/return/{{1}}\", districts, uuid),\n"
                        .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                        ,
                        "ReturnBindingKey = (districts, uuid) => string.Format(\"padding/{0}/return/{{0}}\", uuid),\n"
                        .Basic <ServiceMeta>(meta => meta.Name))
                    .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && client)
                    , Generator.GenSelect(
                        Generator.GenSelect(
                            "ReturnBindingKey = (districts, uuid) => string.Format(\"{{0}}.{0}.return.{{1}}\", districts, uuid),\n"
                            .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                            ,
                            "ReturnBindingKey = (districts, uuid) => string.Format(\"padding.{0}.return.{{1}}\", districts, uuid),\n"
                            .Basic <ServiceMeta>(meta => meta.Name)
                            ).Satisfy(meta => meta.Type == ServiceType.Service))
                    .Satisfy(meta => meta.Scope == ServiceScope.InterServer)

                    );

            var returnRoutingKey =
                Generator.GenSelect(
                    Generator.GenSelect(
                        "ReturnRoutingKey = (districts, uuid) => string.Format(\"{{0}}.{0}.return.{{1}}\", districts, uuid),\n"
                        .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                        , "ReturnRoutingKey = (districts, uuid) => string.Format(\"padding.{0}.return.{{0}}\", uuid),\n"
                        .Basic <ServiceMeta>(meta => meta.Name))
                    .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && !client)
                    , Generator.GenSelect(
                        Generator.GenSelect(
                            "ReturnRoutingKey = (districts, uuid) => string.Format(\"{{0}}.{0}.return.{{1}}\", districts, uuid),\n"
                            .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                            ,
                            "ReturnRoutingKey = (districts, uuid) => string.Format(\"padding.{0}.return.{{1}}\", districts, uuid),\n"
                            .Basic <ServiceMeta>(meta => meta.Name)
                            ).Satisfy(meta => meta.Type == ServiceType.Service))
                    .Satisfy(meta => meta.Scope == ServiceScope.InterServer));

            var returnExchange =
                Generator.GenSelect(
                    "ReturnExchangeName = () => \"amq.topic\",\n".Unit <ServiceMeta>()
                    .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && !client),
                    "ReturnExchangeName = () => \"{0}.return\",\n".Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Scope == ServiceScope.InterServer)
                    ).Satisfy(meta => meta.Type == ServiceType.Service);

            var delegateExchange =
                Generator.GenSelect(
                    "DelegateExchangeName = () => \"amq.topic\",\n".Unit <ServiceMeta>()
                    .Satisfy(meta => meta.Scope == ServiceScope.ServerToClient && !client)
                    ,
                    "DelegateExchangeName = () => \"{0}.notify\",\n".Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Notify && !client)
                    ,
                    "DelegateExchangeName = () => \"{0}.invoke\",\n".Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Service && meta.Scope == ServiceScope.InterServer && !client));

            var implExchange =
                Generator.GenSelect(
                    "ImplExchangeName = () => \"{0}.notify\",\n".Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Notify && !client),
                    "ImplExchangeName = () => \"{0}.invoke\",\n".Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Service && !client));

            var implQueueName =
                Generator.GenSelect(
                    "ImplQueueName = districts=>string.Format(\"{{0}}.{0}.invoke\", districts),\n"
                    .Basic <ServiceMeta>(
                        meta => serviceName.Code(meta)).Satisfy(meta => meta.Divisional)
                    , "ImplQueueName = districts => string.Format(\"padding.{0}.invoke\"),\n".Basic <ServiceMeta>(
                        meta => serviceName.Code(meta)))
                .Satisfy(meta => meta.Type == ServiceType.Service && !client);

            var publishKey =
                Generator.GenSelect(
                    "PublishKey = (districts, uuid) => string.Format(\"{{0}}/{0}/invoke\", districts),\n"
                    .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                    ,
                    "PublishKey = (districts, uuid) => string.Format(\"padding/{0}/invoke\"),\n"
                    .Basic <ServiceMeta>(meta => meta.Name))
                .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && client);

            var subscribeKey =
                Generator.GenSelect(
                    "SubscribeKey = (districts, uuid) => string.Format(\"{{0}}/{0}/sync/{{1}}\", districts, uuid),\n"
                    .Basic <ServiceMeta>(meta => meta.Name)
                    .Satisfy(meta => meta.Type == ServiceType.Sync && meta.Scope == ServiceScope.ServerToClient && client)
                    ,
                    Generator.GenSelect(
                        "SubscribeKey = (districts, uuid) => string.Format(\"{{0}}/{0}/return/{{1}}\", districts, uuid),\n"
                        .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                        ,
                        "SubscribeKey = (districts, uuid) => string.Format(\"padding/{0}/return/{{0}}\", uuid),\n"
                        .Basic <ServiceMeta>(meta => meta.Name))
                    .Satisfy(meta => meta.Scope == ServiceScope.ClientToServer && client));

            var zkServicePath =
                Generator.GenSelect(
                    "ServicePath = (districts) => string.Format(\"/{{0}}/{{1}}\", districts, {0}),\n"
                    .Basic <ServiceMeta>(meta => meta.Name).Satisfy(meta => meta.Divisional)
                    ,
                    "ServicePath = (districts) => string.Format(\"/global/{{1}}\", districts, {0}),\n"
                    .Basic <ServiceMeta>(meta => meta.Name));

            var gateServiceId =
                "ServiceId  = s => {0},"
                .Basic <ServiceMeta>(meta => meta.Id);

            var amqpRule =
                "AmqpRule = new RoutingRule.AmqpRoutingRule()"
                .Unit <ServiceMeta>()
                .Append(
                    implBindingKey
                    .Append(delegateRoutingKey)
                    .Append(returnBindKey)
                    .Append(returnRoutingKey)
                    .Append(returnExchange)
                    .Append(delegateExchange)
                    .Append(implExchange)
                    .Append(implQueueName)
                    .Brace()).WithPostfix(",");

            var mqttRule =
                "MqttRule = new RoutingRule.MqttRoutingRule()"
                .Unit <ServiceMeta>()
                .Append(
                    publishKey
                    .Append(subscribeKey)
                    .Brace()).WithPostfix(",");

            var gateRule =
                "GateRule = new RoutingRule.GateRoutingRule()"
                .Unit <ServiceMeta>()
                .Append(
                    gateServiceId
                    .Brace()).WithPostfix(",");

            var zkRule =
                "ZkRule = new RoutingRule.ZkRoutingRule()"
                .Unit <ServiceMeta>()
                .Append(
                    zkServicePath
                    .Brace()).WithPostfix(",");

            var metaBuilder =
                "MetaData.SetServiceRoutingRule({0}, new RoutingRule()"
                .Basic <ServiceMeta>(meta => meta.Name)
                .Append(
                    amqpRule.SkipLine().Satisfy(_ => !client)
                    .Append(mqttRule.SkipLine().Satisfy(_ => client))
                    .Append(gateRule.SkipLine())
                    .Append(zkRule.SkipLine().Satisfy(_ => !client))
                    .Brace().WithPostfix(");"));

            var metaConstructor =
                implMetaInit.Many("\n").Append(metaBuilder.Many("\n")).Brace().WithPrefix("\nstatic AutoInit()");

            var metaCoder =
                autoInitName.Many("\n")
                .Append(metaConstructor)
                .Append(
                    "public static void Init(){}".Unit <IEnumerable <ServiceMeta> >())
                .Brace().WithPrefix("\npublic static class AutoInit");
            #endregion

            var serviceCoder =
                invokeGenCoder.Satisfy(_ => client)
                .Append(clientImplGenCoder.Satisfy(meta => client).SkipLine())
                .Append(serverImplGenCoder.Satisfy(meta => !client).SkipLine())
                .Append(delegateCoder.Satisfy(meta => (meta.Scope == ServiceScope.ClientToServer && client) || (meta.Scope != ServiceScope.ClientToServer && !client)).WithPostfix("\n"))
                .Append(dispatcherCoder.Satisfy(meta => (meta.Scope != ServiceScope.ServerToClient && !client) || (meta.Scope == ServiceScope.ServerToClient && client)).WithPostfix("\n"))
                .Append(serializerCoder.SkipLine());

            var serviceWithRegion =
                "#region {0}\n{1}#endregion".Basic <ServiceMeta>(serviceName.Code, serviceCoder.Code);

            return
                (metaCoder.WithPostfix("\n")
                 .Append(serviceWithRegion.Many("\n")));
        }