Skip to content

Commit 256f591

Browse files
authored
TryGetPropertyValue on a nested ComplexType returns T, should return Delta<T> #2500 (#2570)
1 parent 2ccbefd commit 256f591

6 files changed

Lines changed: 494 additions & 65 deletions

File tree

src/Microsoft.AspNet.OData.Shared/DeltaOfTStructuralType.cs

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,9 @@ public Delta(Type structuralType, IEnumerable<string> updatableProperties)
9292
public Delta(Type structuralType, IEnumerable<string> updatableProperties,
9393
PropertyInfo dynamicDictionaryPropertyInfo)
9494
: this(structuralType, updatableProperties: updatableProperties, dynamicDictionaryPropertyInfo, false)
95-
{
95+
{
9696
}
9797

98-
9998
/// <summary>
10099
/// Initializes a new instance of <see cref="Delta{TStructuralType}"/>.
101100
/// </summary>
@@ -116,23 +115,18 @@ public Delta(Type structuralType, IEnumerable<string> updatableProperties,
116115
IsComplexType = isComplexType;
117116
}
118117

119-
120-
121118
/// <inheritdoc/>
122-
public override Type StructuredType
123-
=> _structuredType;
119+
public override Type StructuredType => _structuredType;
124120

125121
/// <inheritdoc/>
126-
public override Type ExpectedClrType
127-
=> typeof(TStructuralType);
122+
public override Type ExpectedClrType => typeof(TStructuralType);
128123

129124
/// <summary>
130125
/// The list of property names that can be updated.
131126
/// </summary>
132127
/// <remarks>When the list is modified, any modified properties that were removed from the list are no longer
133128
/// considered to be changed.</remarks>
134-
public IList<string> UpdatableProperties
135-
=> _updatableProperties;
129+
public IList<string> UpdatableProperties => _updatableProperties;
136130

137131
/// <summary>
138132
/// To determine if the StructuralType is a Complex type
@@ -148,9 +142,9 @@ public override void Clear()
148142
/// <inheritdoc/>
149143
public override bool TrySetPropertyValue(string name, object value)
150144
{
151-
if (String.IsNullOrWhiteSpace(name))
145+
if (string.IsNullOrWhiteSpace(name))
152146
{
153-
throw Error.ArgumentNull("name");
147+
throw Error.ArgumentNull(nameof(name));
154148
}
155149

156150
if (_dynamicDictionaryPropertyinfo != null)
@@ -186,7 +180,7 @@ public override bool TryGetPropertyValue(string name, out object value)
186180
{
187181
if (name == null)
188182
{
189-
throw Error.ArgumentNull("name");
183+
throw Error.ArgumentNull(nameof(name));
190184
}
191185

192186
if (_dynamicDictionaryPropertyinfo != null)
@@ -212,6 +206,9 @@ public override bool TryGetPropertyValue(string name, out object value)
212206
Contract.Assert(IsDeltaOfT(deltaNestedResource.GetType()));
213207

214208
// Get the Delta<{NestedResourceType}>._instance using Reflection.
209+
// This semantic is not correct but is preserved for backwards
210+
// compatability and should be replaced in the next major release by
211+
// the code in TryGetNestedPropertyValue.
215212
FieldInfo field = deltaNestedResource.GetType().GetField("_instance", BindingFlags.NonPublic | BindingFlags.Instance);
216213
Contract.Assert(field != null, "field != null");
217214
value = field.GetValue(deltaNestedResource);
@@ -232,12 +229,48 @@ public override bool TryGetPropertyValue(string name, out object value)
232229
return false;
233230
}
234231

232+
/// <summary>
233+
/// Attempts to get the value of the nested Property called <paramref name="name"/> from the underlying Entity.
234+
/// <remarks>
235+
/// Only properties that exist on Entity can be retrieved.
236+
/// Only modified nested properties can be retrieved.
237+
/// The nested Property type will be <see cref="IDelta"/> of its defined type.
238+
/// </remarks>
239+
/// </summary>
240+
/// <param name="name">The name of the nested Property</param>
241+
/// <param name="value">The value of the nested Property</param>
242+
/// <returns><c>True</c> if the Property was found and is a nested Property</returns>
243+
public bool TryGetNestedPropertyValue(string name, out object value)
244+
{
245+
if (name == null)
246+
{
247+
throw Error.ArgumentNull(nameof(name));
248+
}
249+
250+
if (!_deltaNestedResources.ContainsKey(name))
251+
{
252+
value = null;
253+
return false;
254+
}
255+
256+
// This is a nested resource, the value returned must be an IDelta<T>
257+
// from the dictionary of nested resources to allow the traversal of
258+
// hierarchies of Delta<T>.
259+
object deltaNestedResource = _deltaNestedResources[name];
260+
261+
Contract.Assert(deltaNestedResource != null, "deltaNestedResource != null");
262+
Contract.Assert(IsDeltaOfT(deltaNestedResource.GetType()));
263+
264+
value = deltaNestedResource;
265+
return true;
266+
}
267+
235268
/// <inheritdoc/>
236269
public override bool TryGetPropertyType(string name, out Type type)
237270
{
238271
if (name == null)
239272
{
240-
throw Error.ArgumentNull("name");
273+
throw Error.ArgumentNull(nameof(name));
241274
}
242275

243276
if (_dynamicDictionaryPropertyinfo != null)
@@ -314,14 +347,14 @@ public void CopyChangedValues(TStructuralType original)
314347
{
315348
if (original == null)
316349
{
317-
throw Error.ArgumentNull("original");
350+
throw Error.ArgumentNull(nameof(original));
318351
}
319352

320353
// Delta parameter type cannot be derived type of original
321354
// to prevent unrecognizable information from being applied to original resource.
322355
if (!_structuredType.IsAssignableFrom(original.GetType()))
323356
{
324-
throw Error.Argument("original", SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
357+
throw Error.Argument(nameof(original), SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
325358
}
326359

327360
RuntimeHelpers.EnsureSufficientExecutionStack();
@@ -397,7 +430,7 @@ private dynamic ReAssignComplexDerivedType(TStructuralType parent, string nested
397430

398431
//Here original type is the type for original (T) resource.
399432
//We will keep going to base types and finally will get the Common Basetype for the derived complex types in to the originalType variable.
400-
433+
401434
//The new Original type, means the new complex type (T) which will replace the current complex type.
402435
dynamic newOriginalNestedResource = originalValue;
403436

@@ -438,12 +471,12 @@ public void CopyUnchangedValues(TStructuralType original)
438471
{
439472
if (original == null)
440473
{
441-
throw Error.ArgumentNull("original");
474+
throw Error.ArgumentNull(nameof(original));
442475
}
443476

444477
if (!_structuredType.IsInstanceOfType(original))
445478
{
446-
throw Error.Argument("original", SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
479+
throw Error.Argument(nameof(original), SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
447480
}
448481

449482
IEnumerable<PropertyAccessor<TStructuralType>> propertiesToCopy = GetUnchangedPropertyNames().Select(s => _allProperties[s]);
@@ -513,12 +546,12 @@ private static IDictionary<string, object> GetDynamicPropertyDictionary(Property
513546
{
514547
if (propertyInfo == null)
515548
{
516-
throw Error.ArgumentNull("propertyInfo");
549+
throw Error.ArgumentNull(nameof(propertyInfo));
517550
}
518551

519552
if (entity == null)
520553
{
521-
throw Error.ArgumentNull("entity");
554+
throw Error.ArgumentNull(nameof(entity));
522555
}
523556

524557
object propertyValue = propertyInfo.GetValue(entity);
@@ -568,7 +601,7 @@ private void Reset(Type structuralType)
568601
{
569602
if (structuralType == null)
570603
{
571-
throw Error.ArgumentNull("structuralType");
604+
throw Error.ArgumentNull(nameof(structuralType));
572605
}
573606

574607
if (!typeof(TStructuralType).IsAssignableFrom(structuralType))
@@ -629,7 +662,7 @@ private bool IsIgnoredProperty(bool isTypeDataContract, PropertyInfo propertyInf
629662
return !propertyInfo.GetCustomAttributes(typeof(DataMemberAttribute), inherit: true).Any();
630663
}
631664

632-
return propertyInfo.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), inherit: true).Any();
665+
return propertyInfo.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), inherit: true).Any();
633666
}
634667

635668
// Copy changed dynamic properties and leave the unchanged dynamic properties
@@ -733,10 +766,7 @@ private void CopyUnchangedDynamicValues(TStructuralType targetEntity)
733766

734767
private bool TrySetPropertyValueInternal(string name, object value)
735768
{
736-
if (name == null)
737-
{
738-
throw Error.ArgumentNull("name");
739-
}
769+
Debug.Assert(name != null, "Argument name is null");
740770

741771
if (!(_allProperties.ContainsKey(name) && _updatableProperties.Contains(name)))
742772
{
@@ -763,10 +793,7 @@ private bool TrySetPropertyValueInternal(string name, object value)
763793

764794
private bool TrySetNestedResourceInternal(string name, object deltaNestedResource)
765795
{
766-
if (name == null)
767-
{
768-
throw Error.ArgumentNull("name");
769-
}
796+
Debug.Assert(name != null, "Argument name is null");
770797

771798
if (!(_allProperties.ContainsKey(name) && _updatableProperties.Contains(name)))
772799
{

0 commit comments

Comments
 (0)