4

I found a function in c# like this:

  private Dictionary<string, Func<string>> ObtenerExtraCfgCampo(MsgDefCamp camp)
    {
        var extra = new Dictionary<string, Func<string>>();
        extra.Add("Oddity", () => camp.Order % 2 == 0 ? "Even" : "Odd");
        extra.Add("Odd", () => camp.Order % 2 == 0 ? "Odd" : string.Empty);
        extra.Add("Even", () => camp.Order % 2 != 0 ? "Even" : string.Empty);
        extra.Add("MsgPath", () => campo.MsgPath);
        return extra;

    }

Is there any utility on this? wouldn't it be better like this

private Dictionary<string, string> ObtenerExtraCfgCampo(MsgDefCamp camp)
{
    var extra = new Dictionary<string, string>();
    extra.Add("Oddity",  camp.Order % 2 == 0 ? "Even" : "Odd");
    extra.Add("Odd",  camp.Order % 2 == 0 ? "Odd" : string.Empty);
    extra.Add("Even",  camp.Order % 2 != 0 ? "Even" : string.Empty);
    extra.Add("MsgPath",  campo.MsgPath);
    return extra;

}

I undestand that changing camp would change the behavior of the functions. But isn't it too riski and difficult to reason about? I wonder if I'm missing the point of this

  • Instead of thinking of Func<T> as a function that returns a T, instead mentally think of it as ComputedOnDemand<T>. A string is a string. A ComputedOnDemand<string> is a thing that can compute a string when asked. Those are different! – Eric Lippert Oct 17 '18 at 16:15
6

Ignoring the slight differences in type, interacting with the result of the first gives you a view onto the current state of camp, but the second gives a view onto some previous state of camp (I.E. when ObtenerExtraCfgCampo was called, probably billions of nanoseconds ago).

They do different things, so are not interchangeable. It's not any more risky than any other reference to mutable state.

I've just gone through most of an app changing a bunch of Dictionary<Whatever, string>s to Dictionary<Whatever, Func<string>>s so that we can change language at runtime

  • the difference in type actually tells you this as well – jk. Oct 16 '18 at 9:07
  • 1
    @jk not strictly, but it's a strong hint. I've just gone through most of an app changing a bunch of Dictionary<Whatever, string>s to Dictionary<Whatever, Func<string>>s so that we can change language at runtime – Caleth Oct 16 '18 at 9:12
  • @Caleth the Language example that you just said has open my eyes in the ussefullness of this :D – Adrian Godoy Oct 16 '18 at 9:34
3

To see what the point of it is, try running the two versions of the method with mutating data, eg see here for an example of what happens.

The first version, using Func involves a closure over the MsgDefCamp instance. In other words, when the dictionary is interrogated it gets the current value, so in my example, it reports "Even" even though the value was off when the method was called.

The second version evaluates the contents of the MsgDefCamp instance when the method is called and stores those results in the dictionary. So even though the Order changes, the dictionary's value doesn't change and "Odd" is reported.

It can be difficult to reason if you aren't familiar with such code. It is an incredibly useful language feature though, so it's worth becoming familiar with it.

  • On you example, seems that changing both after declaration it stills changes it's value. I would asume that changing msgDefCamp2 would not change the result. – Adrian Godoy Oct 16 '18 at 15:01
  • @AdrianGodoy, my apologies. That was very sloppy of me. I saw the results I was expecting so didn't proof-read the code and so posted a link to nonsense code. I've fixed it and updated the link. – David Arno Oct 16 '18 at 15:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.