Question

For example, consider a utility class SerializableList:

public class SerializableList : List<ISerializable>
{
    public T Add<T>(T item) where T : ISerializable
    {
        base.Add(item);
        return item;
    }

    public T Add<T>(Func<T> factory) where T : ISerializable
    {
        var item = factory();
        base.Add(item);
        return item;
    }
}

Usually I'd use it like this:

var serializableList = new SerializableList(); 
var item1 = serializableList.Add(new Class1());
var item2 = serializableList.Add(new Class2());

I could also have used it via factoring, like this:

var serializableList = new SerializableList(); 
var item1 = serializableList.Add(() => new Class1());
var item2 = serializableList.Add(() => new Class2());

The second approach appears to be a preferred usage pattern, as I've been lately noticing on SO. Is it really so (and why, if yes) or is it just a matter of taste?

Was it helpful?

Solution 2

Caching

In the example you have provided it does not make sense as others have pointed out. Instead I will give you another example,

public class MyClass{
    public MyClass(string file){
        // load a huge file
        // do lots of computing...
        // then store results...
    }
}

private ConcurrentDictionary<string,MyClass> Cache = new ....

public MyClass GetCachedItem(string key){
    return Cache.GetOrAdd(key, k => new MyClass(key));
}

In above example, let's say we are loading a big file and we are calculating something and we are interested in end result of that calculation. To speedup my access, when I try to load files through Cache, Cache will return me cached entry if it has it, only when cache does not find the item, it will call the Factory method, and create new instance of MyClass.

So you are reading files many times, but you are only creating instance of class that holds data just once. This pattern is only useful for caching purpose.

But if you are not caching, and every iteration requires to call new operator, then it makes no sense to use factory pattern at all.

Alternate Error Object or Error Logging

For some reason, if creation fails, List can create an error object, for example,

 T defaultObject = ....

public T Add<T>(Func<T> factory) where T : ISerializable
{
    T item;
    try{
        item = factory();
    }catch(ex){
        Log(ex);
        item = defaultObject;
    }
    base.Add(item);
    return item;
}

In this example, you can monitor factory if it generates an exception while creating new object, and when that happens, you Log the error, and return something else and keep some default value in list. I don't know what will be practical use of this, but Error Logging sounds better candidate here.

OTHER TIPS

Given your example, the factory method is silly. Unless the callee requires the ability to control the point of instantiation, instantiate multiple instances, or lazy evaluation, it's just useless overhead.

The compiler will not be able to optimize out delegate creation.

To reference the examples of using the factory syntax that you gave in comments on the question. Both examples are trying (albeit poorly) to provide guaranteed cleanup of the instances.

If you consider a using statement:

using (var x = new Something()) { }

The naive implementation would be:

var x = new Something();
try 
{ 
}
finally
{
   if ((x != null) && (x is IDisposable))
     ((IDisposable)x).Dispose();
}

The problem with this code is that it is possible for an exception to occur after the assignment of x, but before the try block is entered. If this happens, x will not be properly disposed, because the finally block will not execute. To deal with this, the code for a using statement will actually be something more like:

Something x = null;
try 
{
   x = new Something();
}
finally
{
   if ((x != null) && (x is IDisposable))
      ((IDisposable)x).Dispose();
}

Both of the examples that you reference using factory parameters are attempting to deal with this same issue. Passing a factory allows for the instance to be instantiated within the guarded block. Passing the instance directly allows for the possibility of something to go wrong along the way and not have Dispose() called.

In those cases, passing the factory parameter makes sense.

No, there's no general preference of passing the factory instead of the value. However, in very particular situations, you will prefer to pass the factory method instead of the value.

Think about it:

What's the difference between passing the parameter as a value, or passing it as a factory method (e.g. using Func<T>)?

Answer is simple: order of execution.

  • In the first case, you need to pass the value, so you must obtain it before calling the target method.
  • In the second case, you can postpone the value creation/calculation/obtaining till it's needed by the target method.

Why would you want to postpone the value creation/calculation/obtaining? obvious things come to mind:

  • Processor-intensive or memory-intensive creation of the value, that you want to happen only in case the value is really needed (on-demand). This is Lazy loading then.
  • If the value creation depends on parameters that are accessible by the target method but not from outside of it. So, you would pass Func<T, T> instead of Func<T>.

The question compares methods with different purposes. The second one should be named CreateAndAdd<T>(Func<T> factory).

So depending what functionality is required, should be used one or another method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top