123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- #if !NO_RUNTIME
- using System;
- using System.Net;
- using ProtoBuf.Meta;
- #if FEAT_IKVM
- using Type = IKVM.Reflection.Type;
- using IKVM.Reflection;
- #else
- using System.Reflection;
- #endif
- namespace ProtoBuf.Serializers
- {
- sealed class ParseableSerializer : IProtoSerializer
- {
- private readonly MethodInfo parse;
- public static ParseableSerializer TryCreate(Type type, TypeModel model)
- {
- if (type == null) throw new ArgumentNullException("type");
- #if WINRT || PORTABLE || COREFX
- MethodInfo method = null;
-
- #if WINRT || COREFX
- foreach (MethodInfo tmp in type.GetTypeInfo().GetDeclaredMethods("Parse"))
- #else
- foreach (MethodInfo tmp in type.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly))
- #endif
- {
- ParameterInfo[] p;
- if (tmp.Name == "Parse" && tmp.IsPublic && tmp.IsStatic && tmp.DeclaringType == type && (p = tmp.GetParameters()) != null && p.Length == 1 && p[0].ParameterType == typeof(string))
- {
- method = tmp;
- break;
- }
- }
- #else
- MethodInfo method = type.GetMethod("Parse",
- BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly,
- null, new Type[] { model.MapType(typeof(string)) }, null);
- #endif
- if (method != null && method.ReturnType == type)
- {
- if (Helpers.IsValueType(type))
- {
- MethodInfo toString = GetCustomToString(type);
- if (toString == null || toString.ReturnType != model.MapType(typeof(string))) return null; // need custom ToString, fools
- }
- return new ParseableSerializer(method);
- }
- return null;
- }
- private static MethodInfo GetCustomToString(Type type)
- {
- #if WINRT
- foreach (MethodInfo method in type.GetTypeInfo().GetDeclaredMethods("ToString"))
- {
- if (method.IsPublic && !method.IsStatic && method.GetParameters().Length == 0) return method;
- }
- return null;
- #elif PORTABLE || COREFX
- MethodInfo method = Helpers.GetInstanceMethod(type, "ToString", Helpers.EmptyTypes);
- if (method == null || !method.IsPublic || method.IsStatic || method.DeclaringType != type) return null;
- return method;
- #else
- return type.GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
- null, Helpers.EmptyTypes, null);
- #endif
- }
- private ParseableSerializer(MethodInfo parse)
- {
- this.parse = parse;
- }
- public Type ExpectedType { get { return parse.DeclaringType; } }
- bool IProtoSerializer.RequiresOldValue { get { return false; } }
- bool IProtoSerializer.ReturnsValue { get { return true; } }
- #if !FEAT_IKVM
- public object Read(object value, ProtoReader source)
- {
- Helpers.DebugAssert(value == null); // since replaces
- return parse.Invoke(null, new object[] { source.ReadString() });
- }
- public void Write(object value, ProtoWriter dest)
- {
- ProtoWriter.WriteString(value.ToString(), dest);
- }
- #endif
- #if FEAT_COMPILER
- void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
- {
- Type type = ExpectedType;
- if (Helpers.IsValueType(type))
- { // note that for structs, we've already asserted that a custom ToString
- // exists; no need to handle the box/callvirt scenario
-
- // force it to a variable if needed, so we can take the address
- using (Compiler.Local loc = ctx.GetLocalWithValue(type, valueFrom))
- {
- ctx.LoadAddress(loc, type);
- ctx.EmitCall(GetCustomToString(type));
- }
- }
- else {
- ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("ToString"));
- }
- ctx.EmitBasicWrite("WriteString", valueFrom);
- }
- void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
- {
- ctx.EmitBasicRead("ReadString", ctx.MapType(typeof(string)));
- ctx.EmitCall(parse);
- }
- #endif
- }
- }
- #endif
|