/// <summary> /// Ensure all <see cref="ConfigurableProperties"/> can be converted back and forth to a string in order to be both /// readable from and writable to an <see cref="IPropertyBag"/>. /// </summary> protected void VerifyAllPropertiesSupportRoundTripStringConversion() { ConfigurableProperties.ForEach( p => { var converter = TypeDescriptor.GetConverter(p.PropertyType); var value = new SpecimenContext(CreateAutoFixture()).Resolve(p); if (!converter.CanConvertTo(typeof(string))) { throw new NotSupportedException( $"{converter.GetType().Name} TypeConverter cannot convert a {p.PropertyType.Name} to a string. " + $"{p.PropertyType.Name} must have a dedicated TypeConverter that supports back-and-forth string conversions."); } var serializedValue = (string)converter.ConvertTo(value, typeof(string)); if (serializedValue.IsNullOrEmpty()) { throw new NotSupportedException( $"The conversion to string made by {converter.GetType().Name} of the {p.PropertyType.Name} {p.Name} property returned null for {value}."); } if (!converter.CanConvertFrom(typeof(string))) { throw new NotSupportedException( $"{converter.GetType().Name} TypeConverter cannot convert a string to a {p.PropertyType.Name}. " + $"{p.PropertyType.Name} must have a dedicated TypeConverter that supports back-and-forth string conversions."); } var deserializedValue = converter.ConvertFrom(serializedValue); if (deserializedValue == null) { throw new NotSupportedException( $"The conversion from string made by {converter.GetType().Name} of the {p.PropertyType.Name} {p.Name} property returned null for {serializedValue}."); } if (value is IEnumerable actualEnumerable && deserializedValue is IEnumerable deserializedEnumerable && actualEnumerable.SequenceEqual(deserializedEnumerable)) { return; } if (!value.Equals(deserializedValue)) { throw new NotSupportedException( $"{converter.GetType().Name} TypeConverter could not perform a successful roundtrip conversion of {p.PropertyType.Name} {p.Name} for {value}. " + $"The failure to validate a successful roundtrip conversion could also be due to the fact that {p.PropertyType.Name} does not implement IEquatable<T>."); } }); }