public ClassReflectionInfo(Type target)
        {
            var md = new MethodDict();
            var pd = new PropDict();
            var fd = new FieldDict();
            var overrideItems = new Dictionary<string, List<Tuple<ScriptMemberAttribute, Maybe<ScriptMethodInfo, ScriptPropertyInfo>>>>();

            foreach (var item in target.GetMembers(BindingFlags.NonPublic | BindingFlags.Public
                | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
            {
                var attribute = GetScriptMemberAttribute(item);
                if (attribute == null)
                {
                    continue;
                }

                Maybe<ScriptMethodInfo, ScriptPropertyInfo> maybe = null;

                if (!overrideItems.ContainsKey(attribute.Name))
                {
                    overrideItems[attribute.Name] = new List<Tuple<ScriptMemberAttribute, Maybe<ScriptMethodInfo, ScriptPropertyInfo>>>();
                }
                if (item.MemberType == MemberTypes.Method)
                {

                    var info = new ScriptMethodInfo(item as MethodInfo);
                    md[attribute.Name] = info;
                    maybe = new Maybe<ScriptMethodInfo, ScriptPropertyInfo>(info);
                }
                else if (item.MemberType == MemberTypes.Field)
                {
                    fd[attribute.Name] = item as FieldInfo;//no override
                }
                else if (item.MemberType == MemberTypes.Property)
                {
                    var info = new ScriptPropertyInfo(item as PropertyInfo, attribute);
                    pd[attribute.Name] = info;
                    maybe = new Maybe<ScriptMethodInfo, ScriptPropertyInfo>(info);
                }
                overrideItems[attribute.Name].Add(new Tuple<ScriptMemberAttribute, Maybe<ScriptMethodInfo, ScriptPropertyInfo>>(attribute, maybe));
            }

            foreach (var item in overrideItems.Where(i => i.Value.Count > 1))//スクリプト名が重複しているものの処理
            {
                var exception = new Exception("スクリプト名の重複" + item.Key + item.Value.Select(x => x.Item2.ToString()));
                if (!item.Value.Any(x => x.Item1.IsOverride))
                {
                    throw exception;
                }
                var head = item.Value
                    .Select(x => new { x = x, info = x.Item2.IsT() ? x.Item2.Value1.MethodInfo as MemberInfo : x.Item2.Value2.PropertyInfo as MemberInfo })
                    .MaxBy(x => x.info.DeclaringType.GetBaseTypeTree().Count).x;//一番継承関係が深いもの
                //	.OrderByDescending(x => x, (x, y) => x.info.DeclaringType.GetBaseTypeTree().Count - y.info.DeclaringType.GetBaseTypeTree().Count)
                //	.First().x;
                if (!head.Item1.IsOverride)
                {
                    throw exception;
                }
                else
                {
                    if (head.Item2.IsT())
                    {
                        md[head.Item1.Name] = head.Item2.Value1;
                    }
                    else
                    {
                        pd[head.Item1.Name] = head.Item2.Value2;
                    }
                }

            }
            MethodDict = md;
            PropertyDict = pd;
            FieldDict = fd;
            StaticMethodDict = GetStaticMethods(target);
        }
Example #2
0
        static XElement MethodToXml(ScriptMethodInfo method)
        {
            var root = MemberToXml("method", method.MethodInfo, method.Name);
            //root.Add(NameToXml(method.Attribute.Name));
            root.Add(TypeToXml(method.MethodInfo.ReturnType));
            //root.Add(new XElement("source", method.MethodInfo.Name));
            var param = new XElement("params");
            if (method.DefaultParameterCount > 0)
            {
                var defparam = new XElement("default");
                foreach (var item in method.MethodInfo.GetParameters().Take(method.DefaultParameterCount))
                {
                    defparam.Add(ParameterToXml(item));
                }
                param.Add(defparam);
            }
            if (method.Attribute != null && method.Attribute.OptionName != null && method.Attribute.OptionName.Count() > 0)
            {
                var opt = new XElement("options");
                int index = method.DefaultParameterCount;
                foreach (var item in method.Attribute.OptionName.Zip(method.Attribute.OptionArgNum, (name, num)=>new{name, num}))
                {
                    var option = new XElement("option", NameToXml(item.name));
                    for (int i = 0; i < item.num; i++)
                    {
                        option.Add(ParameterToXml(method.MethodInfo.GetParameters()[index]));
                        index++;
                    }
                    opt.Add(option);

                    //opt.Add(new XElement(,  ParameterToXml(method.MethodInfo.GetParameters()[index])
                }
                param.Add(opt);
            }
            root.Add(param);
            return root;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="method"></param>
        /// <param name="tokens">名前を除いたトークン列</param>
        /// <param name="caller">呼び出し元のインスタンス</param>
        /// <returns></returns>
        Expression CallExternalMethodInner(ScriptMethodInfo method, object[] tokens, Expression caller)
        {
            List<Expression> args = GetArgs(tokens);
            Option[] options = GetOptions(tokens);
            var attribute = method.Attribute;
            var param = method.MethodInfo.GetParameters();
            int index = 0;

            if (args.Count != method.DefaultParameterCount)
            {
                throw new ParseException("外部メソッド呼び出しで必須引数の数が不一致" + method.ToString() + String.Format(" need {0} params but {1} args.", method.DefaultParameterCount, args.Count));
            }
            index += args.Count;

            if (attribute != null && attribute.OptionName != null)//オプションが定義されていれば
            {
                string[] name = attribute.OptionName;
                int[] num = attribute.OptionArgNum;
                var less = options.Select(o => o.Name).Except(name);
                if (less.Any())
                {
                    throw new ParseException(method.Name + "メソッド呼び出しに無効なオプション指定 : " + less.Aggregate((src, dst) => dst + ", " + src));
                }

                for (int i = 0; i < name.Length; i++)
                {
                    Option op = options.FirstOrDefault(o => o.Name == name[i]);
                    int argCount = num[i];
                    if (op != null)
                    {
                        args.AddRange(op.Args.ToArray());
                        index += op.Args.Count();
                        argCount -= op.Args.Count();
                    }
                    if (argCount > 0)
                    {
                        //ValueならNaN, 引数のデフォルト値があればその値、参照型ならNull, それ以外ならValue型の0で埋める
                        args.AddRange(Enumerable.Range(index, argCount).Select(x =>
                        {
                            if (param[x].ParameterType == ValueType) return NanExpression;
                            if (param[x].DefaultValue != DBNull.Value) return Expression.Constant(param[x].DefaultValue);
                            if (param[x].ParameterType.IsClass) return Expression.Constant(null);
                            return Expression.Constant(Activator.CreateInstance(param[x].ParameterType), param[x].ParameterType);
                        }));
                        index += argCount;
                    }

                }
            }
            if (param.Length != args.Count)
            {
                throw new ParseException("外部メソッド呼び出しで引数とパラメータの数の不一致\n" + method.ToString() + String.Format(" need {0} params but {1} args.", param.Length, args.Count));
            }
            for (int i = 0; i < param.Length; i++)
            {
                if (!param[i].ParameterType.IsAssignableFrom(args[i].Type))
                {
                    args[i] = Expression.Convert(args[i], param[i].ParameterType);
                }
            }

            if (caller == null)
            {
                return Expression.Call(method.MethodInfo, args);
            }
            return Expression.Call(caller, method.MethodInfo, args);
        }