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); }
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); }