0

I'm trying to get rid of some code with anonymous functions and classes.

I stuck on this:

public List<Object> Years { get; set; } = GetYears();

private static List<Object> GetYears()
{
    List<Object> retList = new List<Object>();

    retList.Add(new { Value = (byte)255, Name = "Any" });
    retList.Add(new { Value = (byte)254, Name = "None" });

    for (byte i = 0; i < 50; i++)
    {
        retList.Add(new { Value = i, Name = (2000 + i).ToString() });
    }
    return retList;
}

Is it possible to get rid of static GetYears() method?

I mean something like this:

public List<Object> Years { get; set; } = () =>  
{
    List<Object> retList = new List<Object>();
    for (byte i = 0; i < 50; i++)
    {
        retList.Add(new { Value = i, Name = (2000 + i).ToString() });
    }
    return retList;
}

The problem is that the field initializer cannot reference non-static method.

Is it possible to get around this?

Edit: I added these 2 lines of code:

retList.Add(new { Value = (byte)255, Name = "None" });
retList.Add(new { Value = (byte)254, Name = "Any" });
Kamil
  • 13,363
  • 24
  • 88
  • 183
  • It's not what you're asking but you could just put it in the constructor of the class. – Loocid May 31 '19 at 00:38
  • @Loocid But the problem is that I'm working on reducing constructor size and cleaning up huge MVVM ViewModel. – Kamil May 31 '19 at 01:54

2 Answers2

2

Technically speaking, you can do something like this

public class LambdaInitalization {
    public List<Object> Years = ((Func<List<Object>>)(() =>  
    {
        List<Object> retList = new List<Object>();
        for (byte i = 0; i < 50; i++)
        {
            retList.Add(new { Value = i, Name = (2000 + i).ToString() });
        }
        return retList;
    }))();
}

Which creates an anonymous function that returns a List<Object>, then runs it (unfortunately it cannot be implied, it must be an explicit cast).

The much better solution is to just use the constructor, to do pretty much exactly what the constructor exists for.

public class CtorInitalization {
    public List<Object> Years { get; set; }

    public CtorInitalization() {
        Years = new List<Object>();
        for (byte i = 0; i < 50; i++)
        {
            Years.Add(new { Value = i, Name = (2000 + i).ToString() });
        }
    }
}

Funnily enough, the lamda initialization will compile into the constructor anyway, so there is no valid use functionally speaking for defining it outside of the constructor.

See both of these in action here: https://dotnetfiddle.net/1f62Hj

Prime
  • 2,410
  • 1
  • 20
  • 35
1

As mentioned you can't do this by design, an initializer cannot reference the nonstatic field, method, or property 'field', and an anonymous method is not this.

You can put it in the constructor, other options would be to make it a Lazy<T>

public Lazy<List<Object>> Years { get; set; } = new Lazy<List<object>>(() =>
{
   List<object> retList = new List<object>();
   for (byte i = 0; i < 50; i++)
   {
      retList.Add(new { Value = i, Name = (2000 + i).ToString() });
   }
   return retList;
});

or hack it a little with Enumerable.Range

private List<Object> Years { get; set; }
   = Enumerable.Range(0, 50)
               .Select(i => (object)new { Value = i, Name = (2000 + i).ToString() })
               .ToList();

Note : The whole List<object> seems a little suspicious anyway

Or maybe a little more succinct would be a Value Tuple

private List<(int Value, string Name)> Years { get; set; }
   = Enumerable.Range(0, 50)
               .Select(i => (i, (2000 + i).ToString()))
               .ToList();
halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141