Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dictionary<X, Func<Y>> accessing the containing Dictionary from a Func<> within it

This is a bit of a weird one.

I'm building a web application and I was putting together a simple factory-pattern-like thing to handle some object instantiation. I don't like big ugly switch-case blocks, so I tend to do this:

public enum Option
{
    Option1,
    Option2,
    Option3
}

public Dictionary<Option, Func<MyBaseClass>> OptionMapping 
   = new Dictionary<Option, Func<MyBaseClass>>
{
    { Option1, () => new DerivedClassOne() },
    { Option2, () => new DerivedClassTwo() },
    { Option3, () => new DerivedClassThree() }
};

and then the switch block becomes MyBaseClass selectedThing = OptionMapping[currentOption]();.

It occurred to me while writing this code that if you ever had a situation where two options required the same action, you'd end up with the same Func<> in two places, which I'd rather avoid. Assuming for the moment that you can't just refactor some logic to merge those two options into one, I'd like to know if there's a way to get one Func to call the other.

My first thought was this:

public Dictionary<Option, Func<MyBaseClass>> OptionMapping 
   = new Dictionary<Option, Func<MyBaseClass>>
{
    { Option1, () => new DerivedClassOne() },
    { Option2, () => new DerivedClassTwo() },
    { Option3, () => this[Option1]() }
};

but a quick test in LINQPad tells me that doesn't work because of course the this refers to the class in which the code is written, not the Dictionary (apparently I've spent too much time in languages where this is more fickle). My second thought was to change it to () => OptionMapping [Option1](), but that gives an error that you're trying to use OptionMapping before it's initialised. You could of course do this:

public Dictionary<Option, Func<MyBaseClass>> OptionMapping 
   = new Dictionary<Option, Func<MyBaseClass>>
{
    { Option1, () => new DerivedClassOne() },
    { Option2, () => new DerivedClassTwo() }
};
OptionMapping.Add(Option3, () => OptionMapping [Option1]());

which works, but isn't as pretty. So, this question is mostly one of curiosity.

Is there a way to access one element of a Dictionary from another? More generally, does C# have a keyword like this that means "the object I'm inside right now at time of execution", rather than "the containing object at write time"?

EDIT: Originally, the Dictionary was static, so the error I mentioned about using it before it's been initialised wouldn't happen. The static was actually a leftover from pasting in a larger block of code and editing it down, and then copy-pasting the error around.

So, the main answer being posted is about having a separate object to store the Func and then adding that to the Dictionary twice. That makes sense, and is more or less what I went with in the end (for various reasons it also made some of the surrounding code a bit cleaner) but it's kind of avoiding the part of the question I'm most interested in, which is whether it's possible in C# to access the object you're in at runtime, so that an object could access the dictionary (or list, or array, etc) that they're currently within.

like image 859
anaximander Avatar asked Feb 23 '14 12:02

anaximander


People also ask

How do you return a dictionary from a function?

To return a dictionary, first create the dict object within the function body, assign it to a variable your_dict , and return it to the caller of the function using the keyword operation “ return your_dict “.

Is dict () and {} the same?

dict() versus {} Python provides two different ways to initialize dictionaries - probably the most used type in Python codes. If you are interested in performance, you will find a lot of posts where it clearly states that dict() is slower than simply using {}.


1 Answers

This should work:

private static Dictionary<Option, Func<MyBaseClass>> OptionMapping 
   = new Dictionary<Option, Func<MyBaseClass>> {
    { Option.Option1, () => new DerivedClassOne() },
    { Option.Option2, () => new DerivedClassTwo() },
    { Option.Option3, () => OptionMapping[Option.Option2]() }
};

Demo on ideone.

The problem with this approach is that Option3 contains a different Func object, which relies on another Func to produce its output every time you call it.

I think this is not as nice as a solution in which you make a shared Func object explicitly, and place it in the dictionary several times (i.e. your second code snippet, or the alternative below)

private static Dictionary<Option, Func<MyBaseClass>> OptionMapping;
static MyClass() {
    Func<MyBaseClass> makeDerivedTwo = () => new DerivedClassTwo();
    OptionMapping = new Dictionary<Option, Func<MyBaseClass>> {
        { Option.Option1, () => new DerivedClassOne() },
        { Option.Option2, makeDerivedTwo },
        { Option.Option3, makeDerivedTwo }
    };
}
like image 97
Sergey Kalinichenko Avatar answered Sep 25 '22 02:09

Sergey Kalinichenko