35
public class myClass
{
   public myClass(String InstanceName)
   {
      Name = InstanceName;
   }
   public String Name { get; set; }
}

// Now using myClass lazily I have:

Lazy<myClass> myLazy;
Console.WriteLine(myLazy.Value.Name);

My question is how to pass InstanceName to myClass constructor when we are using a lazy instance ?

Xaqron
  • 29,931
  • 42
  • 140
  • 205

4 Answers4

44

Try this:

Lazy<myClass> myLazy = new Lazy<myClass>(() => new myClass(InstanceName));

Remember that the expression is evaluated lazily, so if you change the value of the variable InstanceName before the constructor is called it might not do what you expect.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
8

Lazy has two ways to initialize. The first is using T's default ctor (parameterless)

the second is accepting an Func that has customer initialization logic. you should use the second overload as mentioned here

http://msdn.microsoft.com/en-us/library/dd642329.aspx

3

You can't, Lazy<T> requires a parameterless constructor. You could use the Lazy<T>(Func<T>) constructor though, with a method that initializes the class.

Femaref
  • 60,705
  • 7
  • 138
  • 176
1

I struggled with this today and in my use case, I didn't want to use parameters from the constructor. I wanted to use parameters from a consumer of my type. Something like this.

public class MyClass
{
    private readonly Lazy< **something** > names;
    public MyClass()
    {
        // Initialize the names here
        this.names = new Lazy< **something ** > (() =>
        {
            // do something here based off of a birth date
            // AND
            // only do it one time (the first time the this.names.Value is called
        });
    }

    public string GetName(DateTime birthDate)
    {
        return this.names.Value(birthDate);
    }
}

I tried using the Lazy(Func) constructor as mentioned by @ibrahim's answer like this.

public class MyClass
{
    private readonly Lazy<Func<DateTime,string>> names;
    public MyClass()
    {
        // Initialize the names here
        this.names = new Lazy<Func<DateTime, string>>(birthDate =>
        {
            this.getNamesAndBirthDates().ToDictionary(x => x.Item2, x => x.Item1).TryGetValue(birthDate, out var name);
            return name;
        });
    }

    public string GetName(DateTime birthDate)
    {
        return this.names.Value(birthDate);
    }

    private IEnumerable<(string, DateTime)> getNamesAndBirthDates()
    {
        // returns a list fetching it from where ever...
        return new[]
        {
            ("name", new DateTime(2000, 1, 1))
        };
    }
}

This didn't work the way I wanted. I wanted the following:

this.getNamesAndBirthDates().ToDictionary(x => x.Item2, x => x.Item1).TryGetValue(birthDate, out var name);
return name;

to only be called one time per unique birth date value. It makes sense as to why it works the way it does, it's just that I didn't want it to work like that. I ended up with the following code that allowed me to do all of the things I wanted.

public class MyClass
{
    private readonly Func<DateTime, string> names;
    public MyClass()
    {
        var container = new Dictionary<DateTime, Lazy<string>>();
        // Initialize the names here
        this.names = birthDate =>
        {
            if (container.TryGetValue(birthDate, out var result)) return result.Value;
            result = new Lazy<string>(() =>
            {
                // This code is only executed one time per unique birth date
                this.getNamesAndBirthDates().ToDictionary(x => x.Item2, x => x.Item1).TryGetValue(birthDate, out var name);
                return name;
            });
            container.Add(birthDate, result);
            return result.Value;
        };
    }

    public string GetName(DateTime birthDate)
    {
        return this.names(birthDate);
    }

    private IEnumerable<(string, DateTime)> getNamesAndBirthDates()
    {
        // returns a list fetching it from where ever...
        return new[]
        {
            ("name", new DateTime(2000, 1, 1))
        };
    }
}

Now I get everything I wanted.

  1. Execute a Lazy func with consumer parameters - not constructor parameters.
  2. Ensure that the Lazy build up code is only done one time per unique parameter value (in this case birth date).
  3. Execute the build up lazily. Meaning only execute the build up when needed (but have it defined in the constructor of the MyClass type)

This code is just an simple example. It doesn't really make sense to do what I'm doing here in real life. But I've used this concept in production and it worked good.

Gary Brunton
  • 1,840
  • 1
  • 22
  • 33