Skip to content

ConfigurationBinder fails to bind class that implements IDictionary #77246

@svkuhn

Description

@svkuhn

Description

Binding a Configuration to a class that implements IDictionary<string,T> always results in an empty Dictionary.
The set function throws a System.Reflection.TargetException. I think the problem is that the setter is reflected by Dictionary and not the actual type.

Reproduction Steps

Small test class:

	public class TestDictionaryBinding
	{
		public class CustomDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TKey : notnull
		{

		}

		public class IDictionaryImplementationClass<TKey, TValue> : IDictionary<TKey, TValue> where TKey : notnull
		{
			private Dictionary<TKey, TValue> m_dict = new();

			public TValue this[TKey key] { get => m_dict[key]; set => m_dict[key] = value; }

			public ICollection<TKey> Keys => m_dict.Keys;

			public ICollection<TValue> Values => m_dict.Values;

			public int Count => m_dict.Count;

			public bool IsReadOnly => false;

			public void Add(TKey key, TValue value) => m_dict.Add(key, value);

			public void Add(KeyValuePair<TKey, TValue> item) => m_dict.Add(item.Key, item.Value);

			public void Clear() => m_dict.Clear();

			public bool Contains(KeyValuePair<TKey, TValue> item) => m_dict.Contains(item);

			public bool ContainsKey(TKey key) => m_dict.ContainsKey(key);

			public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) => throw new NotImplementedException();

			public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => m_dict.GetEnumerator();

			public bool Remove(TKey key) => m_dict.Remove(key);

			public bool Remove(KeyValuePair<TKey, TValue> item) => m_dict.Remove(item.Key);
			
			public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => m_dict.TryGetValue(key, out value);

			IEnumerator IEnumerable.GetEnumerator() => m_dict.GetEnumerator();
		}

		[Fact]
		public void Test_InterfaceDictionary()
		{
			var _cfg = new Dictionary<string, string>()
			{
				{ "key", "value" }
			};

			var _config = new ConfigurationBuilder()
				.AddInMemoryCollection(_cfg!)
				.Build();

			var _dictionary = _config.Get<Dictionary<string, string>>(); // success
			var _dictionaryInterface = _config.Get<IDictionary<string, string>>(); // success
			var _customDictionaryClass = _config.Get<CustomDictionary<string, string>>(); // success
			var _customIDictionaryImplementation = _config.Get<IDictionaryImplementationClass<string, string>>(); // empty

			Assert.Single(_dictionary);
			Assert.Single(_dictionaryInterface);
			Assert.Single(_customDictionaryClass);
			Assert.Single(_customIDictionaryImplementation);
		}
	}

Expected behavior

Items from Configuration should be added to a IDictionary implementation

Actual behavior

Custom IDictionary implementation is empty

Regression?

Was working in
7.0.0-preview.7.22375.6

Known Workarounds

No response

Configuration

Used packages for Test:

Other information

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions