Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic class operators derived from interface seems broken #1659

Closed
timdoke opened this issue Nov 27, 2019 · 1 comment
Closed

Generic class operators derived from interface seems broken #1659

timdoke opened this issue Nov 27, 2019 · 1 comment

Comments

@timdoke
Copy link

@timdoke timdoke commented Nov 27, 2019

Let's say I have a CaseInsensitiveConcurrentDictionary. The intention of it is to be interchangeable with regular Dictionary implementations -- where, we always use the interface IDictionary<T, T> to interact with either. Both Dictionary and ConcurrentDictionary implement IDictionary interface members.

The class looks like this:

public class CaseInsensitiveDictionary<TValue>
    : ConcurrentDictionary<string, TValue>
{
    public CaseInsensitiveDictionary()
        : base(StringComparer.InvariantCultureIgnoreCase)
    {
    }

    private CaseInsensitiveDictionary(IDictionary<string, TValue> attributes)
        : this()
    {
        AddRange(attributes);
    }

    public void Add(string key, TValue value)
    {
        this.TryAdd(key, value);
    }

    public void AddRange(IDictionary<string, TValue> entries)
    {
        foreach (var item in entries)
        {
            this.TryAdd(item.Key, item.Value);
        }
    }

    public static CaseInsensitiveDictionary<TValue> Create(IDictionary<string, TValue> attributes = null)
    {
        if (attributes == null)
        {
            return new CaseInsensitiveDictionary<TValue>();
        }
        return new CaseInsensitiveDictionary<TValue>(attributes);
    }

    public static implicit operator Dictionary<string, TValue>(CaseInsensitiveDictionary<TValue> data)
    {
        return new Dictionary<string, TValue>(data);
    }

    public static implicit operator CaseInsensitiveDictionary<TValue>(Dictionary<string, TValue> data)
    {
        return Create(data);
    }

}

`

Let's say then that we are trying to implicitly convert the ConcurrentDictionary to and from a dictionary. To test, I wrote these methods:

    public void FromDictionaryToCaseInsensitiveDictionaryTest()
    {

        Dictionary<string, string> dc2 = new Dictionary<string, string>();
        dc2.Add("test1", "test1 value");

        var dc3 = (CaseInsensitiveDictionary<string>)dc2;
        Console.WriteLine("FromDictionaryToCaseInsensitiveDictionaryTest success");
    }

    public void FromIDictionaryToCaseInsensitiveDictionaryTest()
    {
        IDictionary<string, string> dc2 = new Dictionary<string, string>();
        dc2.Add("test1", "test1 value");

        var dc3 = (CaseInsensitiveDictionary<string>)dc2;

        Console.WriteLine("FromIDictionaryToCaseInsensitiveDictionaryTest success");
    }


    public void FromCaseInsensitiveDictionaryToDictionaryTest()
    {

        var dc2 = new CaseInsensitiveDictionary<string>();
        dc2.Add("test1", "test1 value");

        var dc3 = (Dictionary<string, string>)dc2;

        Console.WriteLine("FromCaseInsensitiveDictionaryToDictionaryTest success");

    }

The first (FromDictionaryToCaseInsensitiveDictionaryTest) and third methods (FromCaseInsensitiveDictionaryToDictionaryTest) work fine and correctly use the operators.

The second one fails with this exception: System.InvalidCastException: 'Unable to cast object of type 'System.Collections.Generic.Dictionary2[System.String,System.String]' to type 'OpenToken.CaseInsensitiveDictionary1[System.String]'.'
. In my opinion, FromIDictionaryToCaseInsensitiveDictionaryTest should work because the type is CaseInsensitiveDictionary and implements IDictionary. If I do NOT have the first conversion operator, the first test method fails with this exact same error message,

With this evidence, it seems to me that something is missing when the runtime is looking for the appropriate operator. FromIDictionaryToCaseInsensitiveDictionaryTest should work either from the Dictionary operator or automatically work because it implements the IDictionary interface. (I cannot create an operator for IDictionary conversion because that is illegal).

Please let me know if this is expected behavior and if there is some workaround for it. This issue seems to be present in all versions of C#.

Thanks!

@timdoke

This comment has been minimized.

Copy link
Author

@timdoke timdoke commented Nov 27, 2019

Moving this issue to https://github.com/dotnet/runtime/issues/368.. Maybe it's more appropriate.. I'll leave it open for one more day (or someone else can close it), if it is not appropriate there..

@timdoke timdoke closed this Nov 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.