From f9e5fa47d7f53c9efa5b5509f438219b8495f7bb Mon Sep 17 00:00:00 2001 From: Josh Close Date: Fri, 21 Jun 2024 10:02:02 -0500 Subject: [PATCH] Added nullable to FastDynamicObject. --- src/CsvHelper/FastDynamicObject.cs | 43 ++-- .../Dynamic/FastDynamicTests.cs | 188 +++++++++--------- 2 files changed, 115 insertions(+), 116 deletions(-) diff --git a/src/CsvHelper/FastDynamicObject.cs b/src/CsvHelper/FastDynamicObject.cs index 33088840e..766715339 100644 --- a/src/CsvHelper/FastDynamicObject.cs +++ b/src/CsvHelper/FastDynamicObject.cs @@ -3,23 +3,22 @@ // See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. // https://github.com/JoshClose/CsvHelper using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.Dynamic; using System.Linq.Expressions; using System.Reflection; namespace CsvHelper; -internal class FastDynamicObject : IDynamicMetaObjectProvider, IDictionary +internal class FastDynamicObject : IDynamicMetaObjectProvider, IDictionary { - private readonly Dictionary dict; + private readonly Dictionary dict; public FastDynamicObject() { - dict = new Dictionary(); + dict = new Dictionary(); } - object IDictionary.this[string key] + object? IDictionary.this[string key] { get { @@ -37,15 +36,15 @@ object IDictionary.this[string key] } } - ICollection IDictionary.Keys => dict.Keys; + ICollection IDictionary.Keys => dict.Keys; - ICollection IDictionary.Values => dict.Values; + ICollection IDictionary.Values => dict.Values; - int ICollection>.Count => dict.Count; + int ICollection>.Count => dict.Count; - bool ICollection>.IsReadOnly => false; + bool ICollection>.IsReadOnly => false; - object SetValue(string key, object value) + object? SetValue(string key, object? value) { dict[key] = value; @@ -57,32 +56,32 @@ DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) return new FastDynamicMetaObject(parameter, BindingRestrictions.Empty, this); } - void IDictionary.Add(string key, object value) + void IDictionary.Add(string key, object? value) { SetValue(key, value); } - void ICollection>.Add(KeyValuePair item) + void ICollection>.Add(KeyValuePair item) { SetValue(item.Key, item.Value); } - void ICollection>.Clear() + void ICollection>.Clear() { dict.Clear(); } - bool ICollection>.Contains(KeyValuePair item) + bool ICollection>.Contains(KeyValuePair item) { return dict.Contains(item); } - bool IDictionary.ContainsKey(string key) + bool IDictionary.ContainsKey(string key) { return dict.ContainsKey(key); } - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { if (arrayIndex < 0 || arrayIndex >= array.Length) { @@ -102,7 +101,7 @@ void ICollection>.CopyTo(KeyValuePair> IEnumerable>.GetEnumerator() + IEnumerator> IEnumerable>.GetEnumerator() { return dict.GetEnumerator(); } @@ -112,24 +111,24 @@ IEnumerator IEnumerable.GetEnumerator() return dict.GetEnumerator(); } - bool IDictionary.Remove(string key) + bool IDictionary.Remove(string key) { return dict.Remove(key); } - bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) { return dict.Remove(item.Key); } - bool IDictionary.TryGetValue(string key, out object value) + bool IDictionary.TryGetValue(string key, out object? value) { return dict.TryGetValue(key, out value!); } private class FastDynamicMetaObject : DynamicMetaObject { - private static readonly MethodInfo getValueMethod = typeof(IDictionary).GetProperty("Item")!.GetGetMethod()!; + private static readonly MethodInfo getValueMethod = typeof(IDictionary).GetProperty("Item")!.GetGetMethod()!; private static readonly MethodInfo setValueMethod = typeof(FastDynamicObject).GetMethod("SetValue", BindingFlags.NonPublic | BindingFlags.Instance)!; public FastDynamicMetaObject(Expression expression, BindingRestrictions restrictions) : base(expression, restrictions) { } @@ -165,7 +164,7 @@ public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, Dy public override IEnumerable GetDynamicMemberNames() { - if (HasValue && Value is IDictionary lookup) + if (HasValue && Value is IDictionary lookup) { return lookup.Keys; } diff --git a/tests/CsvHelper.Tests/Dynamic/FastDynamicTests.cs b/tests/CsvHelper.Tests/Dynamic/FastDynamicTests.cs index c5e82838e..11546c376 100644 --- a/tests/CsvHelper.Tests/Dynamic/FastDynamicTests.cs +++ b/tests/CsvHelper.Tests/Dynamic/FastDynamicTests.cs @@ -1,99 +1,99 @@ -using System; -using System.Collections.Generic; -using Xunit; +using Xunit; -namespace CsvHelper.Tests.Dynamic +namespace CsvHelper.Tests.Dynamic; + +public class FastDynamicObjectTests { - public class FastDynamicObjectTests + [Fact] + public void Dynamic_SetAndGet_Works() + { + dynamic obj = new FastDynamicObject(); + obj.Id = 1; + obj.Name = "one"; + obj.Null = null; + + var id = obj.Id; + var name = obj.Name; + var @null = obj.Null; + + Assert.Equal(1, id); + Assert.Equal("one", name); + Assert.Null(@null); + } + + [Fact] + public void CopyTo_NegativeIndex_Throws() + { + IDictionary d = new FastDynamicObject(); + var a = new KeyValuePair[1]; + + Assert.Throws(() => d.CopyTo(a, -1)); + } + + [Fact] + public void CopyTo_IndexLargerThanArrayLength_Throws() + { + IDictionary d = new FastDynamicObject(); + var a = new KeyValuePair[1]; + + Assert.Throws(() => d.CopyTo(a, a.Length)); + } + + [Fact] + public void CopyTo_SourceIsLargerThanDestination_Throws() + { + IDictionary d = new FastDynamicObject(); + d["a"] = 1; + d["b"] = 2; + var a = new KeyValuePair[1]; + + Assert.Throws(() => d.CopyTo(a, 0)); + } + + [Fact] + public void CopyTo_IndexGreaterThanZeroAndSourceIsLargerThanDestination_Throws() + { + IDictionary d = new FastDynamicObject(); + d["a"] = 1; + d["b"] = 2; + var a = new KeyValuePair[2]; + + Assert.Throws(() => d.CopyTo(a, 1)); + } + + [Fact] + public void CopyTo_StartAtZero_Copies() + { + IDictionary d = new FastDynamicObject(); + d["a"] = 1; + d["b"] = 2; + var a = new KeyValuePair[2]; + + d.CopyTo(a, 0); + + Assert.Equal("a", a[0].Key); + Assert.Equal(1, a[0].Value); + Assert.Equal("b", a[1].Key); + Assert.Equal(2, a[1].Value); + } + + [Fact] + public void CopyTo_StartGreaterThanZero_Copies() { - [Fact] - public void Dynamic_SetAndGet_Works() - { - dynamic obj = new FastDynamicObject(); - obj.Id = 1; - obj.Name = "one"; - - var id = obj.Id; - var name = obj.Name; - - Assert.Equal(1, id); - Assert.Equal("one", name); - } - - [Fact] - public void CopyTo_NegativeIndex_Throws() - { - IDictionary d = new FastDynamicObject(); - var a = new KeyValuePair[1]; - - Assert.Throws(() => d.CopyTo(a, -1)); - } - - [Fact] - public void CopyTo_IndexLargerThanArrayLength_Throws() - { - IDictionary d = new FastDynamicObject(); - var a = new KeyValuePair[1]; - - Assert.Throws(() => d.CopyTo(a, a.Length)); - } - - [Fact] - public void CopyTo_SourceIsLargerThanDestination_Throws() - { - IDictionary d = new FastDynamicObject(); - d["a"] = 1; - d["b"] = 2; - var a = new KeyValuePair[1]; - - Assert.Throws(() => d.CopyTo(a, 0)); - } - - [Fact] - public void CopyTo_IndexGreaterThanZeroAndSourceIsLargerThanDestination_Throws() - { - IDictionary d = new FastDynamicObject(); - d["a"] = 1; - d["b"] = 2; - var a = new KeyValuePair[2]; - - Assert.Throws(() => d.CopyTo(a, 1)); - } - - [Fact] - public void CopyTo_StartAtZero_Copies() - { - IDictionary d = new FastDynamicObject(); - d["a"] = 1; - d["b"] = 2; - var a = new KeyValuePair[2]; - - d.CopyTo(a, 0); - - Assert.Equal("a", a[0].Key); - Assert.Equal(1, a[0].Value); - Assert.Equal("b", a[1].Key); - Assert.Equal(2, a[1].Value); - } - - [Fact] - public void CopyTo_StartGreaterThanZero_Copies() - { - IDictionary d = new FastDynamicObject(); - d["a"] = 1; - d["b"] = 2; - var a = new KeyValuePair[4]; - - d.CopyTo(a, 1); - - Assert.Null(a[0].Key); - Assert.Null(a[0].Value); - Assert.Equal("a", a[1].Key); - Assert.Equal(1, a[1].Value); - Assert.Equal("b", a[2].Key); - Assert.Equal(2, a[2].Value); - Assert.Null(a[3].Key); - Assert.Null(a[3].Value); - } + IDictionary d = new FastDynamicObject(); + d["a"] = 1; + d["b"] = 2; + var a = new KeyValuePair[4]; + + d.CopyTo(a, 1); + + Assert.Null(a[0].Key); + Assert.Null(a[0].Value); + Assert.Equal("a", a[1].Key); + Assert.Equal(1, a[1].Value); + Assert.Equal("b", a[2].Key); + Assert.Equal(2, a[2].Value); + Assert.Null(a[3].Key); + Assert.Null(a[3].Value); } }