Browse Source

Merge pull request #660 from jskeet/throw-on-null

Throw on null for string/bytes single fields
Jan Tattermusch 10 năm trước cách đây
mục cha
commit
bde01d5326

+ 1 - 1
Makefile.am

@@ -107,6 +107,7 @@ csharp_EXTRA_DIST=                                                           \
   csharp/src/Google.Protobuf/LimitedInputStream.cs                           \
   csharp/src/Google.Protobuf/LimitedInputStream.cs                           \
   csharp/src/Google.Protobuf/MessageExtensions.cs                            \
   csharp/src/Google.Protobuf/MessageExtensions.cs                            \
   csharp/src/Google.Protobuf/MessageParser.cs                                \
   csharp/src/Google.Protobuf/MessageParser.cs                                \
+  csharp/src/Google.Protobuf/Preconditions.cs                                \
   csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs                      \
   csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs                      \
   csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs                    \
   csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs                    \
   csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs                    \
   csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs                    \
@@ -133,7 +134,6 @@ csharp_EXTRA_DIST=                                                           \
   csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs             \
   csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs             \
   csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs                 \
   csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs                 \
   csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs               \
   csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs               \
-  csharp/src/Google.Protobuf/ThrowHelper.cs                                  \
   csharp/src/Google.Protobuf/WellKnownTypes/Any.cs                           \
   csharp/src/Google.Protobuf/WellKnownTypes/Any.cs                           \
   csharp/src/Google.Protobuf/WellKnownTypes/Api.cs                           \
   csharp/src/Google.Protobuf/WellKnownTypes/Api.cs                           \
   csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs                      \
   csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs                      \

+ 3 - 3
csharp/src/AddressBook/Addressbook.cs

@@ -76,7 +76,7 @@ namespace Google.Protobuf.Examples.AddressBook {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -94,7 +94,7 @@ namespace Google.Protobuf.Examples.AddressBook {
     public string Email {
     public string Email {
       get { return email_; }
       get { return email_; }
       set {
       set {
-        email_ = value ?? "";
+        email_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -257,7 +257,7 @@ namespace Google.Protobuf.Examples.AddressBook {
         public string Number {
         public string Number {
           get { return number_; }
           get { return number_; }
           set {
           set {
-            number_ = value ?? "";
+            number_ = pb::Preconditions.CheckNotNull(value, "value");
           }
           }
         }
         }
 
 

+ 10 - 0
csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs

@@ -111,6 +111,16 @@ namespace Google.Protobuf
             Assert.IsNull(message.OneofNestedMessage);
             Assert.IsNull(message.OneofNestedMessage);
         }
         }
 
 
+        [Test]
+        public void NullStringAndBytesRejected()
+        {
+            var message = new TestAllTypes();
+            Assert.Throws<ArgumentNullException>(() => message.SingleString = null);
+            Assert.Throws<ArgumentNullException>(() => message.OneofString = null);
+            Assert.Throws<ArgumentNullException>(() => message.SingleBytes = null);
+            Assert.Throws<ArgumentNullException>(() => message.OneofBytes = null);
+        }
+
         [Test]
         [Test]
         public void RoundTrip_Empty()
         public void RoundTrip_Empty()
         {
         {

+ 11 - 11
csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs

@@ -426,7 +426,7 @@ namespace Google.Protobuf.TestProtos {
     public string SingleString {
     public string SingleString {
       get { return singleString_; }
       get { return singleString_; }
       set {
       set {
-        singleString_ = value ?? "";
+        singleString_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -435,7 +435,7 @@ namespace Google.Protobuf.TestProtos {
     public pb::ByteString SingleBytes {
     public pb::ByteString SingleBytes {
       get { return singleBytes_; }
       get { return singleBytes_; }
       set {
       set {
-        singleBytes_ = value ?? pb::ByteString.Empty;
+        singleBytes_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -700,7 +700,7 @@ namespace Google.Protobuf.TestProtos {
     public string OneofString {
     public string OneofString {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
       set {
       set {
-        oneofField_ = value ?? "";
+        oneofField_ = pb::Preconditions.CheckNotNull(value, "value");
         oneofFieldCase_ = OneofFieldOneofCase.OneofString;
         oneofFieldCase_ = OneofFieldOneofCase.OneofString;
       }
       }
     }
     }
@@ -709,7 +709,7 @@ namespace Google.Protobuf.TestProtos {
     public pb::ByteString OneofBytes {
     public pb::ByteString OneofBytes {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
       set {
       set {
-        oneofField_ = value ?? pb::ByteString.Empty;
+        oneofField_ = pb::Preconditions.CheckNotNull(value, "value");
         oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
         oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
       }
       }
     }
     }
@@ -2703,7 +2703,7 @@ namespace Google.Protobuf.TestProtos {
     public string StringField {
     public string StringField {
       get { return stringField_; }
       get { return stringField_; }
       set {
       set {
-        stringField_ = value ?? "";
+        stringField_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2954,7 +2954,7 @@ namespace Google.Protobuf.TestProtos {
     public string MyString {
     public string MyString {
       get { return myString_; }
       get { return myString_; }
       set {
       set {
-        myString_ = value ?? "";
+        myString_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -3385,7 +3385,7 @@ namespace Google.Protobuf.TestProtos {
     public string Data {
     public string Data {
       get { return data_; }
       get { return data_; }
       set {
       set {
-        data_ = value ?? "";
+        data_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -3589,7 +3589,7 @@ namespace Google.Protobuf.TestProtos {
     public pb::ByteString Data {
     public pb::ByteString Data {
       get { return data_; }
       get { return data_; }
       set {
       set {
-        data_ = value ?? pb::ByteString.Empty;
+        data_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -3695,7 +3695,7 @@ namespace Google.Protobuf.TestProtos {
     public pb::ByteString Data {
     public pb::ByteString Data {
       get { return data_; }
       get { return data_; }
       set {
       set {
-        data_ = value ?? pb::ByteString.Empty;
+        data_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -4350,7 +4350,7 @@ namespace Google.Protobuf.TestProtos {
     public string FooString {
     public string FooString {
       get { return fooCase_ == FooOneofCase.FooString ? (string) foo_ : ""; }
       get { return fooCase_ == FooOneofCase.FooString ? (string) foo_ : ""; }
       set {
       set {
-        foo_ = value ?? "";
+        foo_ = pb::Preconditions.CheckNotNull(value, "value");
         fooCase_ = FooOneofCase.FooString;
         fooCase_ = FooOneofCase.FooString;
       }
       }
     }
     }
@@ -5409,7 +5409,7 @@ namespace Google.Protobuf.TestProtos {
     public string A {
     public string A {
       get { return a_; }
       get { return a_; }
       set {
       set {
-        a_ = value ?? "";
+        a_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 

+ 8 - 8
csharp/src/Google.Protobuf/Collections/MapField.cs

@@ -112,13 +112,13 @@ namespace Google.Protobuf.Collections
 
 
         public bool ContainsKey(TKey key)
         public bool ContainsKey(TKey key)
         {
         {
-            ThrowHelper.ThrowIfNull(key, "key");
+            Preconditions.CheckNotNullUnconstrained(key, "key");
             return map.ContainsKey(key);
             return map.ContainsKey(key);
         }
         }
 
 
         public bool Remove(TKey key)
         public bool Remove(TKey key)
         {
         {
-            ThrowHelper.ThrowIfNull(key, "key");
+            Preconditions.CheckNotNullUnconstrained(key, "key");
             LinkedListNode<KeyValuePair<TKey, TValue>> node;
             LinkedListNode<KeyValuePair<TKey, TValue>> node;
             if (map.TryGetValue(key, out node))
             if (map.TryGetValue(key, out node))
             {
             {
@@ -151,7 +151,7 @@ namespace Google.Protobuf.Collections
         {
         {
             get
             get
             {
             {
-                ThrowHelper.ThrowIfNull(key, "key");
+                Preconditions.CheckNotNullUnconstrained(key, "key");
                 TValue value;
                 TValue value;
                 if (TryGetValue(key, out value))
                 if (TryGetValue(key, out value))
                 {
                 {
@@ -161,11 +161,11 @@ namespace Google.Protobuf.Collections
             }
             }
             set
             set
             {
             {
-                ThrowHelper.ThrowIfNull(key, "key");
+                Preconditions.CheckNotNullUnconstrained(key, "key");
                 // value == null check here is redundant, but avoids boxing.
                 // value == null check here is redundant, but avoids boxing.
                 if (value == null && !allowNullValues)
                 if (value == null && !allowNullValues)
                 {
                 {
-                    ThrowHelper.ThrowIfNull(value, "value");
+                    Preconditions.CheckNotNullUnconstrained(value, "value");
                 }
                 }
                 LinkedListNode<KeyValuePair<TKey, TValue>> node;
                 LinkedListNode<KeyValuePair<TKey, TValue>> node;
                 var pair = new KeyValuePair<TKey, TValue>(key, value);
                 var pair = new KeyValuePair<TKey, TValue>(key, value);
@@ -187,7 +187,7 @@ namespace Google.Protobuf.Collections
 
 
         public void Add(IDictionary<TKey, TValue> entries)
         public void Add(IDictionary<TKey, TValue> entries)
         {
         {
-            ThrowHelper.ThrowIfNull(entries, "entries");
+            Preconditions.CheckNotNull(entries, "entries");
             foreach (var pair in entries)
             foreach (var pair in entries)
             {
             {
                 Add(pair.Key, pair.Value);
                 Add(pair.Key, pair.Value);
@@ -374,7 +374,7 @@ namespace Google.Protobuf.Collections
 
 
         void IDictionary.Remove(object key)
         void IDictionary.Remove(object key)
         {
         {
-            ThrowHelper.ThrowIfNull(key, "key");
+            Preconditions.CheckNotNull(key, "key");
             if (!(key is TKey))
             if (!(key is TKey))
             {
             {
                 return;
                 return;
@@ -403,7 +403,7 @@ namespace Google.Protobuf.Collections
         {
         {
             get
             get
             {
             {
-                ThrowHelper.ThrowIfNull(key, "key");
+                Preconditions.CheckNotNull(key, "key");
                 if (!(key is TKey))
                 if (!(key is TKey))
                 {
                 {
                     return null;
                     return null;

+ 1 - 1
csharp/src/Google.Protobuf/Google.Protobuf.csproj

@@ -96,7 +96,7 @@
     <Compile Include="Reflection\RepeatedFieldAccessor.cs" />
     <Compile Include="Reflection\RepeatedFieldAccessor.cs" />
     <Compile Include="Reflection\ServiceDescriptor.cs" />
     <Compile Include="Reflection\ServiceDescriptor.cs" />
     <Compile Include="Reflection\SingleFieldAccessor.cs" />
     <Compile Include="Reflection\SingleFieldAccessor.cs" />
-    <Compile Include="ThrowHelper.cs" />
+    <Compile Include="Preconditions.cs" />
     <Compile Include="WellKnownTypes\Any.cs" />
     <Compile Include="WellKnownTypes\Any.cs" />
     <Compile Include="WellKnownTypes\Api.cs" />
     <Compile Include="WellKnownTypes\Api.cs" />
     <Compile Include="WellKnownTypes\Duration.cs" />
     <Compile Include="WellKnownTypes\Duration.cs" />

+ 1 - 1
csharp/src/Google.Protobuf/JsonFormatter.cs

@@ -120,7 +120,7 @@ namespace Google.Protobuf
 
 
         public string Format(IMessage message)
         public string Format(IMessage message)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
+            Preconditions.CheckNotNull(message, "message");
             StringBuilder builder = new StringBuilder();
             StringBuilder builder = new StringBuilder();
             // TODO(jonskeet): Handle well-known types here.
             // TODO(jonskeet): Handle well-known types here.
             // Our reflection support needs improving so that we can get at the descriptor
             // Our reflection support needs improving so that we can get at the descriptor

+ 14 - 14
csharp/src/Google.Protobuf/MessageExtensions.cs

@@ -41,8 +41,8 @@ namespace Google.Protobuf
     {
     {
         public static void MergeFrom(this IMessage message, byte[] data)
         public static void MergeFrom(this IMessage message, byte[] data)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
-            ThrowHelper.ThrowIfNull(data, "data");
+            Preconditions.CheckNotNull(message, "message");
+            Preconditions.CheckNotNull(data, "data");
             CodedInputStream input = CodedInputStream.CreateInstance(data);
             CodedInputStream input = CodedInputStream.CreateInstance(data);
             message.MergeFrom(input);
             message.MergeFrom(input);
             input.CheckLastTagWas(0);
             input.CheckLastTagWas(0);
@@ -50,8 +50,8 @@ namespace Google.Protobuf
 
 
         public static void MergeFrom(this IMessage message, ByteString data)
         public static void MergeFrom(this IMessage message, ByteString data)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
-            ThrowHelper.ThrowIfNull(data, "data");
+            Preconditions.CheckNotNull(message, "message");
+            Preconditions.CheckNotNull(data, "data");
             CodedInputStream input = data.CreateCodedInput();
             CodedInputStream input = data.CreateCodedInput();
             message.MergeFrom(input);
             message.MergeFrom(input);
             input.CheckLastTagWas(0);
             input.CheckLastTagWas(0);
@@ -59,8 +59,8 @@ namespace Google.Protobuf
 
 
         public static void MergeFrom(this IMessage message, Stream input)
         public static void MergeFrom(this IMessage message, Stream input)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
-            ThrowHelper.ThrowIfNull(input, "input");
+            Preconditions.CheckNotNull(message, "message");
+            Preconditions.CheckNotNull(input, "input");
             CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
             CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
             message.MergeFrom(codedInput);
             message.MergeFrom(codedInput);
             codedInput.CheckLastTagWas(0);
             codedInput.CheckLastTagWas(0);
@@ -68,8 +68,8 @@ namespace Google.Protobuf
 
 
         public static void MergeDelimitedFrom(this IMessage message, Stream input)
         public static void MergeDelimitedFrom(this IMessage message, Stream input)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
-            ThrowHelper.ThrowIfNull(input, "input");
+            Preconditions.CheckNotNull(message, "message");
+            Preconditions.CheckNotNull(input, "input");
             int size = (int) CodedInputStream.ReadRawVarint32(input);
             int size = (int) CodedInputStream.ReadRawVarint32(input);
             Stream limitedStream = new LimitedInputStream(input, size);
             Stream limitedStream = new LimitedInputStream(input, size);
             message.MergeFrom(limitedStream);
             message.MergeFrom(limitedStream);
@@ -77,7 +77,7 @@ namespace Google.Protobuf
 
 
         public static byte[] ToByteArray(this IMessage message)
         public static byte[] ToByteArray(this IMessage message)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
+            Preconditions.CheckNotNull(message, "message");
             byte[] result = new byte[message.CalculateSize()];
             byte[] result = new byte[message.CalculateSize()];
             CodedOutputStream output = CodedOutputStream.CreateInstance(result);
             CodedOutputStream output = CodedOutputStream.CreateInstance(result);
             message.WriteTo(output);
             message.WriteTo(output);
@@ -87,8 +87,8 @@ namespace Google.Protobuf
 
 
         public static void WriteTo(this IMessage message, Stream output)
         public static void WriteTo(this IMessage message, Stream output)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
-            ThrowHelper.ThrowIfNull(output, "output");
+            Preconditions.CheckNotNull(message, "message");
+            Preconditions.CheckNotNull(output, "output");
             CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
             CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
             message.WriteTo(codedOutput);
             message.WriteTo(codedOutput);
             codedOutput.Flush();
             codedOutput.Flush();
@@ -96,8 +96,8 @@ namespace Google.Protobuf
 
 
         public static void WriteDelimitedTo(this IMessage message, Stream output)
         public static void WriteDelimitedTo(this IMessage message, Stream output)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
-            ThrowHelper.ThrowIfNull(output, "output");
+            Preconditions.CheckNotNull(message, "message");
+            Preconditions.CheckNotNull(output, "output");
             CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
             CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
             codedOutput.WriteRawVarint32((uint)message.CalculateSize());
             codedOutput.WriteRawVarint32((uint)message.CalculateSize());
             message.WriteTo(codedOutput);
             message.WriteTo(codedOutput);
@@ -106,7 +106,7 @@ namespace Google.Protobuf
 
 
         public static ByteString ToByteString(this IMessage message)
         public static ByteString ToByteString(this IMessage message)
         {
         {
-            ThrowHelper.ThrowIfNull(message, "message");
+            Preconditions.CheckNotNull(message, "message");
             return ByteString.AttachBytes(message.ToByteArray());
             return ByteString.AttachBytes(message.ToByteArray());
         }        
         }        
     }
     }

+ 2 - 2
csharp/src/Google.Protobuf/MessageParser.cs

@@ -84,7 +84,7 @@ namespace Google.Protobuf
         /// <returns>The newly parsed message.</returns>
         /// <returns>The newly parsed message.</returns>
         public T ParseFrom(byte[] data)
         public T ParseFrom(byte[] data)
         {
         {
-            ThrowHelper.ThrowIfNull(data, "data");
+            Preconditions.CheckNotNull(data, "data");
             T message = factory();
             T message = factory();
             message.MergeFrom(data);
             message.MergeFrom(data);
             return message;
             return message;
@@ -92,7 +92,7 @@ namespace Google.Protobuf
 
 
         public T ParseFrom(ByteString data)
         public T ParseFrom(ByteString data)
         {
         {
-            ThrowHelper.ThrowIfNull(data, "data");
+            Preconditions.CheckNotNull(data, "data");
             T message = factory();
             T message = factory();
             message.MergeFrom(data);
             message.MergeFrom(data);
             return message;
             return message;

+ 73 - 52
csharp/src/Google.Protobuf/ThrowHelper.cs → csharp/src/Google.Protobuf/Preconditions.cs

@@ -1,53 +1,74 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-
-namespace Google.Protobuf
-{
-    /// <summary>
-    /// Helper methods for throwing exceptions
-    /// </summary>
-    internal static class ThrowHelper
-    {
-        /// <summary>
-        /// Throws an ArgumentNullException if the given value is null.
-        /// </summary>
-        internal static void ThrowIfNull(object value, string name)
-        {
-            if (value == null)
-            {
-                throw new ArgumentNullException(name);
-            }
-        }
-    }
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Helper methods for throwing exceptions
+    /// </summary>
+    public static class Preconditions
+    {
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        public static T CheckNotNull<T>(T value, string name) where T : class
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        /// <remarks>
+        /// This is equivalent to <see cref="CheckNotNull"/> but without the type parameter
+        /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
+        /// with a value type - but it gets in the way if either you want to use it with a nullable
+        /// value type, or you want to use it with an unconstrained type parameter.
+        /// </remarks>
+        internal static T CheckNotNullUnconstrained<T>(T value, string name)
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+    }
 }
 }

+ 26 - 26
csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs

@@ -301,7 +301,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -310,7 +310,7 @@ namespace Google.Protobuf.Reflection {
     internal string Package {
     internal string Package {
       get { return package_; }
       get { return package_; }
       set {
       set {
-        package_ = value ?? "";
+        package_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -393,7 +393,7 @@ namespace Google.Protobuf.Reflection {
     internal string Syntax {
     internal string Syntax {
       get { return syntax_; }
       get { return syntax_; }
       set {
       set {
-        syntax_ = value ?? "";
+        syntax_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -649,7 +649,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1200,7 +1200,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1236,7 +1236,7 @@ namespace Google.Protobuf.Reflection {
     internal string TypeName {
     internal string TypeName {
       get { return typeName_; }
       get { return typeName_; }
       set {
       set {
-        typeName_ = value ?? "";
+        typeName_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1245,7 +1245,7 @@ namespace Google.Protobuf.Reflection {
     internal string Extendee {
     internal string Extendee {
       get { return extendee_; }
       get { return extendee_; }
       set {
       set {
-        extendee_ = value ?? "";
+        extendee_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1254,7 +1254,7 @@ namespace Google.Protobuf.Reflection {
     internal string DefaultValue {
     internal string DefaultValue {
       get { return defaultValue_; }
       get { return defaultValue_; }
       set {
       set {
-        defaultValue_ = value ?? "";
+        defaultValue_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1545,7 +1545,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1653,7 +1653,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1809,7 +1809,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -1973,7 +1973,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2132,7 +2132,7 @@ namespace Google.Protobuf.Reflection {
     internal string Name {
     internal string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2141,7 +2141,7 @@ namespace Google.Protobuf.Reflection {
     internal string InputType {
     internal string InputType {
       get { return inputType_; }
       get { return inputType_; }
       set {
       set {
-        inputType_ = value ?? "";
+        inputType_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2150,7 +2150,7 @@ namespace Google.Protobuf.Reflection {
     internal string OutputType {
     internal string OutputType {
       get { return outputType_; }
       get { return outputType_; }
       set {
       set {
-        outputType_ = value ?? "";
+        outputType_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2383,7 +2383,7 @@ namespace Google.Protobuf.Reflection {
     internal string JavaPackage {
     internal string JavaPackage {
       get { return javaPackage_; }
       get { return javaPackage_; }
       set {
       set {
-        javaPackage_ = value ?? "";
+        javaPackage_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2392,7 +2392,7 @@ namespace Google.Protobuf.Reflection {
     internal string JavaOuterClassname {
     internal string JavaOuterClassname {
       get { return javaOuterClassname_; }
       get { return javaOuterClassname_; }
       set {
       set {
-        javaOuterClassname_ = value ?? "";
+        javaOuterClassname_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2437,7 +2437,7 @@ namespace Google.Protobuf.Reflection {
     internal string GoPackage {
     internal string GoPackage {
       get { return goPackage_; }
       get { return goPackage_; }
       set {
       set {
-        goPackage_ = value ?? "";
+        goPackage_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2491,7 +2491,7 @@ namespace Google.Protobuf.Reflection {
     internal string ObjcClassPrefix {
     internal string ObjcClassPrefix {
       get { return objcClassPrefix_; }
       get { return objcClassPrefix_; }
       set {
       set {
-        objcClassPrefix_ = value ?? "";
+        objcClassPrefix_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -2500,7 +2500,7 @@ namespace Google.Protobuf.Reflection {
     internal string CsharpNamespace {
     internal string CsharpNamespace {
       get { return csharpNamespace_; }
       get { return csharpNamespace_; }
       set {
       set {
-        csharpNamespace_ = value ?? "";
+        csharpNamespace_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -3853,7 +3853,7 @@ namespace Google.Protobuf.Reflection {
     internal string IdentifierValue {
     internal string IdentifierValue {
       get { return identifierValue_; }
       get { return identifierValue_; }
       set {
       set {
-        identifierValue_ = value ?? "";
+        identifierValue_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -3889,7 +3889,7 @@ namespace Google.Protobuf.Reflection {
     internal pb::ByteString StringValue {
     internal pb::ByteString StringValue {
       get { return stringValue_; }
       get { return stringValue_; }
       set {
       set {
-        stringValue_ = value ?? pb::ByteString.Empty;
+        stringValue_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -3898,7 +3898,7 @@ namespace Google.Protobuf.Reflection {
     internal string AggregateValue {
     internal string AggregateValue {
       get { return aggregateValue_; }
       get { return aggregateValue_; }
       set {
       set {
-        aggregateValue_ = value ?? "";
+        aggregateValue_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -4095,7 +4095,7 @@ namespace Google.Protobuf.Reflection {
         internal string NamePart_ {
         internal string NamePart_ {
           get { return namePart_; }
           get { return namePart_; }
           set {
           set {
-            namePart_ = value ?? "";
+            namePart_ = pb::Preconditions.CheckNotNull(value, "value");
           }
           }
         }
         }
 
 
@@ -4350,7 +4350,7 @@ namespace Google.Protobuf.Reflection {
         internal string LeadingComments {
         internal string LeadingComments {
           get { return leadingComments_; }
           get { return leadingComments_; }
           set {
           set {
-            leadingComments_ = value ?? "";
+            leadingComments_ = pb::Preconditions.CheckNotNull(value, "value");
           }
           }
         }
         }
 
 
@@ -4359,7 +4359,7 @@ namespace Google.Protobuf.Reflection {
         internal string TrailingComments {
         internal string TrailingComments {
           get { return trailingComments_; }
           get { return trailingComments_; }
           set {
           set {
-            trailingComments_ = value ?? "";
+            trailingComments_ = pb::Preconditions.CheckNotNull(value, "value");
           }
           }
         }
         }
 
 

+ 2 - 2
csharp/src/Google.Protobuf/WellKnownTypes/Any.cs

@@ -71,7 +71,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string TypeUrl {
     public string TypeUrl {
       get { return typeUrl_; }
       get { return typeUrl_; }
       set {
       set {
-        typeUrl_ = value ?? "";
+        typeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -80,7 +80,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public pb::ByteString Value {
     public pb::ByteString Value {
       get { return value_; }
       get { return value_; }
       set {
       set {
-        value_ = value ?? pb::ByteString.Empty;
+        value_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 

+ 5 - 5
csharp/src/Google.Protobuf/WellKnownTypes/Api.cs

@@ -84,7 +84,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -109,7 +109,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Version {
     public string Version {
       get { return version_; }
       get { return version_; }
       set {
       set {
-        version_ = value ?? "";
+        version_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -285,7 +285,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -294,7 +294,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string RequestTypeUrl {
     public string RequestTypeUrl {
       get { return requestTypeUrl_; }
       get { return requestTypeUrl_; }
       set {
       set {
-        requestTypeUrl_ = value ?? "";
+        requestTypeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -312,7 +312,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string ResponseTypeUrl {
     public string ResponseTypeUrl {
       get { return responseTypeUrl_; }
       get { return responseTypeUrl_; }
       set {
       set {
-        responseTypeUrl_ = value ?? "";
+        responseTypeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs

@@ -71,7 +71,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string FileName {
     public string FileName {
       get { return fileName_; }
       get { return fileName_; }
       set {
       set {
-        fileName_ = value ?? "";
+        fileName_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs

@@ -224,7 +224,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string StringValue {
     public string StringValue {
       get { return kindCase_ == KindOneofCase.StringValue ? (string) kind_ : ""; }
       get { return kindCase_ == KindOneofCase.StringValue ? (string) kind_ : ""; }
       set {
       set {
-        kind_ = value ?? "";
+        kind_ = pb::Preconditions.CheckNotNull(value, "value");
         kindCase_ = KindOneofCase.StringValue;
         kindCase_ = KindOneofCase.StringValue;
       }
       }
     }
     }

+ 6 - 6
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs

@@ -105,7 +105,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -327,7 +327,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -336,7 +336,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string TypeUrl {
     public string TypeUrl {
       get { return typeUrl_; }
       get { return typeUrl_; }
       set {
       set {
-        typeUrl_ = value ?? "";
+        typeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -610,7 +610,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -783,7 +783,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -932,7 +932,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Name {
     public string Name {
       get { return name_; }
       get { return name_; }
       set {
       set {
-        name_ = value ?? "";
+        name_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 

+ 2 - 2
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs

@@ -822,7 +822,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public string Value {
     public string Value {
       get { return value_; }
       get { return value_; }
       set {
       set {
-        value_ = value ?? "";
+        value_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 
@@ -928,7 +928,7 @@ namespace Google.Protobuf.WellKnownTypes {
     public pb::ByteString Value {
     public pb::ByteString Value {
       get { return value_; }
       get { return value_; }
       set {
       set {
-        value_ = value ?? pb::ByteString.Empty;
+        value_ = pb::Preconditions.CheckNotNull(value, "value");
       }
       }
     }
     }
 
 

+ 0 - 11
src/google/protobuf/compiler/csharp/csharp_field_base.cc

@@ -127,17 +127,6 @@ void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
   }
   }
 }
 }
 
 
-void FieldGeneratorBase::AddNullCheck(io::Printer* printer) {
-  AddNullCheck(printer, "value");
-}
-
-void FieldGeneratorBase::AddNullCheck(io::Printer* printer, const std::string& name) {
-  if (is_nullable_type()) {
-    printer->Print("  pb::ThrowHelper.ThrowIfNull($name$, \"$name$\");\n",
-                   "name", name);
-  }
-}
-
 void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
 void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
 }
 }

+ 2 - 2
src/google/protobuf/compiler/csharp/csharp_primitive_field.cc

@@ -81,7 +81,7 @@ void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
   } else {
   } else {
     printer->Print(
     printer->Print(
       variables_,
       variables_,
-      "    $name$_ = value ?? $default_value$;\n");
+      "    $name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n");
   }
   }
   printer->Print(
   printer->Print(
     "  }\n"
     "  }\n"
@@ -183,7 +183,7 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
     } else {
     } else {
       printer->Print(
       printer->Print(
         variables_,
         variables_,
-        "    $oneof_name$_ = value ?? $default_value$;\n");
+        "    $oneof_name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n");
     }
     }
     printer->Print(
     printer->Print(
       variables_,
       variables_,