1

I am new to C#. I am trying to implement a Dictionary in C# whose Java-equivalent is:

HashMap<string, Variable<?>> dictionary

Here is the detailed Java version of what I'm trying to do: Java how to manage user-defined variables

In C# so far I have something like this:

interface IVariable { }

public class Variable<T> : IVariable
{
    public T myValue { get; set; }
}

Dictionary<string, IVariable> vars = new Dictionary<string, IVariable>();

Then I try to do this:

Variable<int> age = new Variable<int>();
age.myValue = 12;
vars.Add("age", age);
IVariable theVar;
if (vars.TryGetValue("age", out theVar) {
   Console.WriteLine("fetched age is " + theVar.myValue);
}

I run into trouble in the last line because the compiler doesn't recognize the myValue member of a theVar because it is an IVariable.

In this simple example maybe I could declare theVar to be a Variable<int> instead of an IVariable but I haven't tried it because it would require a priori knowledge about what kind of variable I'm fetching from the dictionary and I might not always have that knowledge.

I wouldn't mind if myValue were an inherited/abstract property (if there is such a thing), since every Variable will have a property named myValue (each will differ in type but not in name). In that case I guess I could make IVariable an abstract class rather than an interface, but then I still run into trouble as far as what to put for the type of myValue.

Could I do a cast of theVar into something using as by first checking its type with is? I'm not sure if that would work or is even possible.

I've looked at these posts for guidance (especially the second one):

Wildcard equivalent in C# generics

C# Generics: wildcards

However, my situation is still slightly different than the second example above because that example has an abstract method that is returning a void whereas I wish to have my variables return non-void generic values.

Thanks for any help.

Thus Spoke Nomad
  • 2,372
  • 4
  • 17
  • 34
skrilmps
  • 625
  • 2
  • 10
  • 29

4 Answers4

2

C# has dynamic. You can create Dictionary<string, dynamic>

Or you can use object (boxing/unboxing) Dictionary<string, object>

Or you can get generic type from class

class MyClass<TDicValue>
{
    Dictionary<strint, TDicValue> myDictionary;
}
Thus Spoke Nomad
  • 2,372
  • 4
  • 17
  • 34
  • 1
    Unfortunately I cannot use dynamic because I'm using Unity and dynamic isn't supported. So I tried using boxing/unboxing. I posted my solution below, please take a look and let me know if it will work. Thanks! – skrilmps Jan 30 '17 at 21:51
  • I'm not using Unity, please try it yourself. Also you may do it with generic type coming from class declaration. – Thus Spoke Nomad Jan 30 '17 at 21:55
  • I'm sorry, I didn't mean for that to sound like I was asking you to type it in and test it for me! I worded that poorly. What I meant was, could you take a look at my post and see what you think of the solution? I did type it into Unity and test it and it does work. But just because code works doesn't mean it's bulletproof. :) – skrilmps Jan 30 '17 at 22:49
1

I had this same problem where I had 20 slightly different types and I had to keep dictionaries on. I wanted to organize them in a list.

The problem was the same, selecting the right kind from the list with reflection or strings lacked the ability to provide a type to return to. @skrilmps answer is correct, but packing and and unpacking was at best unreliable without a lot (metric ton) of ugly messy code.

While unity does support dynamics in 2020, this doesn't exactly work with what i am doing unless I make like everything dynamic safe and that's shamble coding, not extensible or maintainable, and just sounds like a general nightmare.

I personally feel that I am an inadequate programmer after years of trying to learn and still not having my efforts provide a productive return or product of note, so i cannot claim the answer being mine, but in my research on the proper solution to this problem i found this: https://www.youtube.com/watch?v=A7qwuFnyIpM

In here he says basically if you add an interface to your similar classes that are intended for use in a variety of different lists, that you can instead make a list of that type of interface. I would assume dictionary as well, and then you can add any kind of class implementing this interface to this singular interface type defined list.

DCCoder
  • 1,587
  • 4
  • 16
  • 29
1

// The following should resolve the boxing problem and now is totally generic:

public interface IVariable<T>
{
    T GetContent();
    void SetContent(T value);
    Type GetDataType();
}

public class Variable<T> : IVariable
{
    private T content;

    public T GetContent()
    {
        return content;
    }

    public void SetContent(T value)
    {
        content = value;
    }

    public Type GetDataType() { return GetType(); }
}

Dictionary<string, Variable<T>> variables = new Dictionary<string, Variable<T>>();
0

I tried using boxing/unboxing and came up with this solution. It appears to work... so far. But it doesn't seem very safe.

public interface Variable
{
    object getValue();
    void setValue(object value);
    Type myType();
}

public class Variable<T>: Variable
{
    private T myValue;

    public object getValue() 
    {
        return myValue;
    }

    public void setValue(object value)
    {
        myValue = (T)value;
    }

    public Type myType() { return myValue.GetType(); }
}

    Dictionary<string, Variable> vars = new Dictionary<string, Variable>();

    Variable<int> age = new Variable<int>();
    age.setValue(21);
    vars.Add("age", age);
    Variable theAgeVar;
    vars.TryGetValue("age", out theAgeVar);
    Console.WriteLine("age = " + theAgeVar.getValue());

    Variable<double> height = new Variable<double>();
    height.setValue(5.9);
    Variable theHeightVar;
    vars.TryGetValue("age", out theHeightVar);
    Debug.Log("height = " + theHeightVar.getValue());

This prints:

age = 21

height = 5.9

One thing I do not like is that I had to make the return type of getValue() be an object. If I wanted myValue (which is of type T) to implement IComparable, for instance, then this information is lost when the boxing happens and the caller receives an object.

skrilmps
  • 625
  • 2
  • 10
  • 29