5

If I have

public class Stats : Dictionary<string, double>
{
}

public class Info : Dictionary<string, Stats>
{
}

and

var data = new Dictionary<string, Dictionary<string, double>> {
    { "1", new Dictionary<string, double> {  { "a", 11 } } },
    { "2", new Dictionary<string, double> {  { "aa", 111 } } },
};

Why can't I do:

var test = (Info)data;

and what operator or code do I need to use in order to be able to instance my

[class inheriting from a Dictionary<string, Dictionary<string, double>>]

from a

Dictionary<string, Dictionary<string, double>>?

Bruno
  • 4,685
  • 7
  • 54
  • 105
  • You cannot instantiate from a base class and then use it as an object of inherited class. What do you want to do with that? – Ashkan S Aug 01 '16 at 23:17
  • 1
    @AshkanSirous: Well the class is just to clean up code and use my class name instead of `Dictionary>` everywhere – Bruno Aug 01 '16 at 23:18
  • I guess you have some functionalities with that object. right? make a class and give that object as a property of the class and encapsulate it with the functionalities. By the way it seems like a wrong design to me. did you wanted to have 2 values with 1 key? why do you have a dictionary of a dictionary? – Ashkan S Aug 01 '16 at 23:22
  • here you can find the way to inherit from a dictionary: http://stackoverflow.com/questions/1594997/how-do-i-inherit-from-dictionary – Ashkan S Aug 01 '16 at 23:22
  • it will work the same way if you have a dictionary of a dictionary, but I am quit sure that you have a wrong design – Ashkan S Aug 01 '16 at 23:23

1 Answers1

6

There are really two different mistakes in your approach here:

  1. Dictionary<string, Stats> is not the same as Dictionary<string, Dictionary<string, double>>. It's wrong to think of Info as inheriting Dictionary<string, Dictionary<string, double>>. It inherits Dictionary<string, Stats>, which is completely different.
  2. Even if you get the right base type, you cannot just go around casting any random instance of a base type to a derived type. See Convert/Cast base type to Derived type for one of the many existing Stack Overflow Q&A topics that discuss this.

Without a good Minimal, Complete, and Verifiable code example it's impossible to know for sure how your code works or what would be needed to get it to do what you want. But in your particular example, you might be able to declare an explicit conversion, which would be invoked when you use the cast operator.

For example:

public class Info : Dictionary<string, Stats>
{
    public static explicit operator Info(Dictionary<string, Dictionary<string, double>> source)
    {
        Info result = new Info();

        foreach (var kvp in source)
        {
            result.Add(kvp.Key, Stats.FromDictionary(kvp.Value));
        }

        return result;
    }
}

where:

public class Stats : Dictionary<string, double>
{
    public static Stats FromDictionary(Dictionary<string, double> source)
    {
        Stats result = new Stats();

        foreach (var kvp in source)
        {
            result.Add(kvp.Key, kvp.Value);
        }

        return result;
    }
}

Ideally, we'd like to be able to do something similar in Info:

public class Stats : Dictionary<string, double>
{
    public static explicit operator Stats(Dictionary<string, double> source)
    {
        Stats result = new Stats();

        foreach (var kvp in source)
        {
            result.Add(kvp.Key, kvp.Value);
        }

        return result;
    }
}

But this is a compiler error:

Stats.explicit operator Stats(System.Collections.Generic.Dictionary)': user-defined conversions to or from a base class are not allowed

This is addressed more thoroughly here: User-defined conversion operator from base class. The short version is that if the compiler allowed this, it would be ambiguous as to what the intent was if you tried to cast from a base reference to the derived reference. The language forces you to be explicit in this case.

Then the statement you want to use would work:

var test = (Info)data;

All that said, in the comments you wrote this:

the class is just to clean up code and use my class name instead of Dictionary<string, Dictionary<string, double>> everywhere

If that's the case, then instead of inheritance, maybe you just want to use type name aliasing. For example:

using Stats = System.Collections.Generic.Dictionary<string, double>;
using Info = System.Collections.Generic
    .Dictionary<string, System.Collections.Generic.Dictionary<string, double>>;

Then you can use the names Stats and Info interchangeably with Dictionary<string, double> and Dictionary<string, Dictionary<string, double>>, respectively.

Community
  • 1
  • 1
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • I learned a good code. thanks. :) By the way, I've never ended up in such situation. why would someone need a dictionary of a dictionary. seems a bit odd to me – Ashkan S Aug 01 '16 at 23:26
  • I get an error `Stats.explicit operator Stats(System.Collections.Generic.Dictionary)': user-defined conversions to or from a base class are not allowed` on the declaration of the explicit operator for Stats...would you happen to know why? – Bruno Aug 01 '16 at 23:31
  • 1
    @Ibiza: oh, oops. I forgot about that. A good explanation is here: [User-defined conversion operator from base class](http://stackoverflow.com/q/3401084). I'll update the answer to address this. – Peter Duniho Aug 01 '16 at 23:36
  • Using `using` will work. But unfortunately, Visual Studio does not provide good support for aliasing. Right-clicking `Stats` or `Info` in the code and selecting "Go to Definition" will bring you to the definition of generic `Dictionary`. And "Go to Declaration" seem plainly broken. Alas. – Alex Fainshtein Jun 20 '22 at 10:05