Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,16 @@ private static void BindInstance(
return;
}

// for sets and read-only set interfaces, we clone what's there into a new collection, if we can
// -----------------------------------------------------------------------------------------------------------------------------
// | bindingPoint | bindingPoint |
// Interface | Value | IsReadOnly | Behavior
// -----------------------------------------------------------------------------------------------------------------------------
// ISet<T> | not null | true/false | Use the Value instance to populate the configuration
// ISet<T> | null | false | Create HashSet<T> instance to populate the configuration
// ISet<T> | null | true | nothing
// IReadOnlySet<T> | null/not null | false | Create HashSet<T> instance, copy over existing values, and populate the configuration
// IReadOnlySet<T> | null/not null | true | nothing
// -----------------------------------------------------------------------------------------------------------------------------
if (TypeIsASetInterface(type))
{
if (!bindingPoint.IsReadOnly || bindingPoint.Value is not null)
Expand All @@ -329,15 +338,25 @@ private static void BindInstance(
return;
}

// For other mutable interfaces like ICollection<>, IDictionary<,> and ISet<>, we prefer copying values and setting them
// on a new instance of the interface over populating the existing instance implementing the interface.
// This has already been done, so there's not need to check again.
if (TypeIsADictionaryInterface(type) && !bindingPoint.IsReadOnly)
// -----------------------------------------------------------------------------------------------------------------------------
// | bindingPoint | bindingPoint |
// Interface | Value | IsReadOnly | Behavior
// -----------------------------------------------------------------------------------------------------------------------------
// IDictionary<T> | not null | true/false | Use the Value instance to populate the configuration
// IDictionary<T> | null | false | Create Dictionary<T> instance to populate the configuration
// IDictionary<T> | null | true | nothing
// IReadOnlyDictionary<T> | null/not null | false | Create Dictionary<K,V> instance, copy over existing values, and populate the configuration
// IReadOnlyDictionary<T> | null/not null | true | nothing
// -----------------------------------------------------------------------------------------------------------------------------
if (TypeIsADictionaryInterface(type))
{
object? newValue = BindDictionaryInterface(bindingPoint.Value, type, config, options);
if (newValue != null)
if (!bindingPoint.IsReadOnly || bindingPoint.Value is not null)
{
bindingPoint.SetValue(newValue);
object? newValue = BindDictionaryInterface(bindingPoint.Value, type, config, options);
if (!bindingPoint.IsReadOnly && newValue != null)
{
bindingPoint.SetValue(newValue);
}
}

return;
Expand Down Expand Up @@ -538,7 +557,7 @@ private static bool CanBindToTheseConstructorParameters(ParameterInfo[] construc
if (addMethod is null || source is null)
{
dictionaryType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
var dictionary = Activator.CreateInstance(dictionaryType);
object? dictionary = Activator.CreateInstance(dictionaryType);
addMethod = dictionaryType.GetMethod("Add", DeclaredOnlyLookup);

var orig = source as IEnumerable;
Expand Down Expand Up @@ -748,9 +767,9 @@ private static Array BindArray(Type type, IEnumerable? source, IConfiguration co
{
Type elementType = type.GetGenericArguments()[0];

bool keyTypeIsEnum = elementType.IsEnum;
bool elementTypeIsEnum = elementType.IsEnum;

if (elementType != typeof(string) && !keyTypeIsEnum)
if (elementType != typeof(string) && !elementTypeIsEnum)
{
// We only support string and enum keys
return null;
Expand Down