Vippy
Vippy

Reputation: 1422

C# Dictionary with Named/Labeled Types

I've searched just about everywhere and not even sure it's possible, but what the hey, I thought I would see what you C# wizards might have for a solution or workaround.

TL;DR:

I have a multi-dimensional collection using C# dictionaries and want to indicate what each string in the dictionary is for, something like this:

private Dictionary<string: Area, Dictionary<string: Controller, string: Action>> ActionCollection;

Which of-course does not work. For now I'm just commenting the dictionary.

Suggestions, thoughts, ideas?

Upvotes: 10

Views: 8376

Answers (4)

Jeroen van Langen
Jeroen van Langen

Reputation: 22073

You cannot do that, but you could add a summary.

For example:

/// <summary>
/// Dictionary<Area, Dictionary<Controller, Action>>
/// </summary>
private Dictionary<string, Dictionary<string, string>> ActionCollection;

These comments will show up in the intellisense.


Or:

If you want to extract info with reflection, you could use custom attributes


If it is just for readability, you could create aliases for it:

using Area = System.String;
using Controller = System.String;
using Action = System.String;

namespace MyApp
{
    public class MyClass
    {
        private Dictionary<Area, Dictionary<Controller, Action>> ActionCollection;
    }
}

But intellisense will show string


@MMM says about invalid xml, you can do this:

/// <summary>
/// Dictionary&lt;Area, Dictionary&lt;Controller, Action&gt;&gt;
/// </summary>

Upvotes: 12

p__d
p__d

Reputation: 463

It's possible by using Tuple Field Names within List:

private List<(string Area, List<(string Controller, string Action)>)> ActionCollection;

That's feature from C# 7.0 or from .NET 4.3 by importing System.ValueTuple nuget.

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726699

Make a class that pairs the key or the value with the annotation:

class AnnotatedVal {
    public string Val {get;}
    public string Annotation {get;}
    public AnnotatedVal(string val, string annotation) {
        // Do null checking
        Val = val;
        Annotation = annotation;
    }
    public bool Equals(object obj) {
        var other = obj as AnnotatedVal;
        return other != null && other.Val == Val && other.Annotation == Annotation;
    }
    public int GetHashCode() {
        return 31*Val.GetHashCode() + Annotation.GetHashCode();
    }
}

private Dictionary<AnnotatedVal,Dictionary<AnnotatedVal,AnnotatedVal>> ActionCollection;

Now you can use AnnotatedVal in your dictionaries to assure segregation:

ActionCollection.Add(new AnnotatedVal("hello", "Area"), someDictionary);
if (ActionCollection.ContainsKey(new AnnotatedVal("hello", "Area"))) {
    Console.WriteLine("Yes");
} else {
    Console.WriteLine("No");
}
if (ActionCollection.ContainsKey(new AnnotatedVal("hello", "Controller"))) {
    Console.WriteLine("Yes");
} else {
    Console.WriteLine("No");
}

The above should produce

Yes
No

because AnnotatedVal("hello", "Area") and AnnotatedVal("hello", "Controller") use different annotations.

Upvotes: 1

tinstaafl
tinstaafl

Reputation: 6948

You could wrap each string in it's own class. Then the declaration and intellisense will be descriptive:

public class Area
{
    public string area { get; set; }
    public override string ToString()
    {
        return area;
    }
}
public class Controller
{
    public string controller { get; set; }
    public override string ToString()
    {
        return controller;
    }
}
public class Action
{
    public string action { get; set; }
    public override string ToString()
    {
        return action;
    }
}
private Dictionary<Area, Dictionary<Controller, Action>> ActionCollection;

Upvotes: 0

Related Questions