diff --git a/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs b/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs index 84c53e267a..92e8a07caf 100644 --- a/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs +++ b/src/ProtocolBuffers/FieldAccess/ReflectionUtil.cs @@ -71,7 +71,7 @@ namespace Google.ProtocolBuffers.FieldAccess // Convert the reflection call into an open delegate, i.e. instead of calling x.Method() // we'll call getter(x). Func getter = - (Func) Delegate.CreateDelegate(typeof(Func), null, method); + (Func)FrameworkPortability.CreateDelegate(typeof(Func), null, method); // Implicit upcast to object (within the delegate) return delegate(TSource source) { return getter(source); }; @@ -93,7 +93,7 @@ namespace Google.ProtocolBuffers.FieldAccess // Convert the reflection call into an open delegate, i.e. instead of calling x.Method(y) we'll // call Method(x, y) Action call = - (Action) Delegate.CreateDelegate(typeof(Action), null, method); + (Action)FrameworkPortability.CreateDelegate(typeof(Action), null, method); return delegate(TSource source, object parameter) { call(source, (TParam) parameter); }; } @@ -116,7 +116,7 @@ namespace Google.ProtocolBuffers.FieldAccess // Convert the reflection call into an open delegate, i.e. instead of calling x.Method(y) we'll // call Method(x, y) Func call = (Func) - Delegate.CreateDelegate(typeof(Func), null, + FrameworkPortability.CreateDelegate(typeof(Func), null, method); return delegate(TSource source, object parameter) { call(source, (TParam) parameter); }; @@ -134,7 +134,7 @@ namespace Google.ProtocolBuffers.FieldAccess public static Func CreateStaticUpcastDelegateImpl(MethodInfo method) { - Func call = (Func) Delegate.CreateDelegate(typeof(Func), null, method); + Func call = (Func)FrameworkPortability.CreateDelegate(typeof(Func), null, method); return delegate { return (IBuilder) call(); }; } } diff --git a/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs b/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs index fd2c72b16f..0a173fea33 100644 --- a/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs +++ b/src/ProtocolBuffers/FieldAccess/RepeatedPrimitiveAccessor.cs @@ -84,10 +84,9 @@ namespace Google.ProtocolBuffers.FieldAccess { throw new ArgumentException("Not all required properties/methods available"); } - clearDelegate = - (Func) Delegate.CreateDelegate(typeof(Func), null, clearMethod); - countDelegate = (Func) Delegate.CreateDelegate - (typeof(Func), null, countProperty.GetGetMethod()); + clearDelegate = (Func) + FrameworkPortability.CreateDelegate(typeof(Func), null, clearMethod); + countDelegate = (Func)FrameworkPortability.CreateDelegate(typeof(Func), null, countProperty.GetGetMethod()); getValueDelegate = ReflectionUtil.CreateUpcastDelegate(messageProperty.GetGetMethod()); addValueDelegate = ReflectionUtil.CreateDowncastDelegateIgnoringReturn(addMethod); getRepeatedWrapperDelegate = ReflectionUtil.CreateUpcastDelegate(builderProperty.GetGetMethod()); diff --git a/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs b/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs index 7d20ea756b..e52af03dce 100644 --- a/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs +++ b/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs @@ -69,9 +69,9 @@ namespace Google.ProtocolBuffers.FieldAccess clrType = messageProperty.PropertyType; hasDelegate = (Func) - Delegate.CreateDelegate(typeof(Func), null, hasProperty.GetGetMethod()); + FrameworkPortability.CreateDelegate(typeof(Func), null, hasProperty.GetGetMethod()); clearDelegate = - (Func) Delegate.CreateDelegate(typeof(Func), null, clearMethod); + (Func)FrameworkPortability.CreateDelegate(typeof(Func), null, clearMethod); getValueDelegate = ReflectionUtil.CreateUpcastDelegate(messageProperty.GetGetMethod()); setValueDelegate = ReflectionUtil.CreateDowncastDelegate(builderProperty.GetSetMethod()); } diff --git a/src/ProtocolBuffers/MessageStreamIterator.cs b/src/ProtocolBuffers/MessageStreamIterator.cs index f5d9bcbe02..89fda91fcf 100644 --- a/src/ProtocolBuffers/MessageStreamIterator.cs +++ b/src/ProtocolBuffers/MessageStreamIterator.cs @@ -38,7 +38,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; -using System.Reflection; namespace Google.ProtocolBuffers { @@ -56,122 +55,45 @@ namespace Google.ProtocolBuffers private readonly ExtensionRegistry extensionRegistry; private readonly int sizeLimit; - // Type.EmptyTypes isn't present on the compact framework - private static readonly Type[] EmptyTypes = new Type[0]; - /// - /// Delegate created via reflection trickery (once per type) to create a builder - /// and read a message from a CodedInputStream with it. Note that unlike in Java, - /// there's one static field per constructed type. + /// The default instance of TMessage type used to construct builders while reading /// - private static readonly Func messageReader = BuildMessageReader(); - + private static readonly TMessage defaultMessageInstance = CreateDefaultInstance(); /// - /// Any exception (within reason) thrown within messageReader is caught and rethrown in the constructor. + /// Any exception (within reason) thrown in type ctor is caught and rethrown in the constructor. /// This makes life a lot simpler for the caller. /// private static Exception typeInitializationException; + /// - /// Creates the delegate later used to read messages. This is only called once per type, but to - /// avoid exceptions occurring at confusing times, if this fails it will set typeInitializationException - /// to the appropriate error and return null. + /// Vastly simplified the reflection to simply obtain the default instance and use it to construct + /// the weak builder while simply casting the result. Ideally this class should have required a + /// TBuilder type argument with a new() constraint to construct the initial instance thereby the + /// reflection could be eliminated. /// - private static Func BuildMessageReader() + private static TMessage CreateDefaultInstance() { try { - Type builderType = FindBuilderType(); - - // Yes, it's redundant to find this again, but it's only the once... - MethodInfo createBuilderMethod = typeof(TMessage).GetMethod("CreateBuilder", EmptyTypes); - Delegate builderBuilder = Delegate.CreateDelegate( - typeof(Func<>).MakeGenericType(builderType), null, createBuilderMethod); - - MethodInfo buildMethod = typeof(MessageStreamIterator) - .GetMethod("BuildImpl", BindingFlags.Static | BindingFlags.NonPublic) - .MakeGenericMethod(typeof(TMessage), builderType); - - return (Func) Delegate.CreateDelegate( - typeof(Func), builderBuilder, buildMethod); + return (TMessage)typeof(TMessage) + .GetProperty("DefaultInstance", typeof(TMessage), new Type[0]) + .GetValue(null, null); } - catch (ArgumentException e) + catch (Exception e) { typeInitializationException = e; + return default(TMessage); } - catch (InvalidOperationException e) - { - typeInitializationException = e; - } - catch (InvalidCastException e) - { - // Can't see why this would happen, but best to know about it. - typeInitializationException = e; - } - return null; - } - - /// - /// Works out the builder type for TMessage, or throws an ArgumentException to explain why it can't. - /// - private static Type FindBuilderType() - { - MethodInfo createBuilderMethod = typeof(TMessage).GetMethod("CreateBuilder", EmptyTypes); - if (createBuilderMethod == null) - { - throw new ArgumentException("Message type " + typeof(TMessage).FullName + - " has no CreateBuilder method."); - } - if (createBuilderMethod.ReturnType == typeof(void)) - { - throw new ArgumentException("CreateBuilder method in " + typeof(TMessage).FullName + - " has void return type"); - } - Type builderType = createBuilderMethod.ReturnType; - Type messageInterface = typeof(IMessage<,>).MakeGenericType(typeof(TMessage), builderType); - Type builderInterface = typeof(IBuilder<,>).MakeGenericType(typeof(TMessage), builderType); - if (Array.IndexOf(typeof(TMessage).GetInterfaces(), messageInterface) == -1) - { - throw new ArgumentException("Message type " + typeof(TMessage) + " doesn't implement " + - messageInterface.FullName); - } - if (Array.IndexOf(builderType.GetInterfaces(), builderInterface) == -1) - { - throw new ArgumentException("Builder type " + typeof(TMessage) + " doesn't implement " + - builderInterface.FullName); - } - return builderType; - } - -// This is only ever fetched by reflection, so the compiler may -// complain that it's unused -#pragma warning disable 0169 - /// - /// Method we'll use to build messageReader, with the first parameter fixed to TMessage.CreateBuilder. Note that we - /// have to introduce another type parameter (TMessage2) as we can't constrain TMessage for just a single method - /// (and we can't do it at the type level because we don't know TBuilder). However, by constraining TMessage2 - /// to not only implement IMessage appropriately but also to derive from TMessage2, we can avoid doing a cast - /// for every message; the implicit reference conversion will be fine. In practice, TMessage2 and TMessage will - /// be the same type when we construct the generic method by reflection. - /// - private static TMessage BuildImpl(Func builderBuilder, CodedInputStream input, - ExtensionRegistry registry) - where TBuilder : IBuilder - where TMessage2 : TMessage, IMessage - { - TBuilder builder = builderBuilder(); - input.ReadMessage(builder, registry); - return builder.Build(); } -#pragma warning restore 0414 private static readonly uint ExpectedTag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); private MessageStreamIterator(StreamProvider streamProvider, ExtensionRegistry extensionRegistry, int sizeLimit) { - if (messageReader == null) + if (ReferenceEquals(defaultMessageInstance, null)) { - throw typeInitializationException; + throw new System.Reflection.TargetInvocationException(typeInitializationException); } this.streamProvider = streamProvider; this.extensionRegistry = extensionRegistry; @@ -224,7 +146,9 @@ namespace Google.ProtocolBuffers { if ((tag == 0 && name == "item") || (tag == ExpectedTag)) { - yield return messageReader(input, extensionRegistry); + IBuilder builder = defaultMessageInstance.WeakCreateBuilderForType(); + input.ReadMessage(builder, extensionRegistry); + yield return (TMessage)builder.WeakBuild(); } else {