Question

I have a set of methods each of which return an ObservableCollection for various types of T, and would like to be able to write a factory method that returns these methods, based on an enum value sent in. For example, suppose I have the following highly realistic methods...

public ObservableCollection<Gribble> GetGribbles() {
  return new ObservableCollection<Gribble>();
}

public ObservableCollection<Gribulator> GenerateGribulators() {
  return new ObservableCollection<Gribulator>();
}

public ObservableCollection<Knepple> MakeKnepples() {
  return new ObservableCollection<Knepple>();
}

...and the following enum...

public enum ListNames {
  Gribbles,
  Gribulators,
  Knepple
}

Then I would like to be able to do this...

Func<ObservableCollection<Gribble>> someGribbles = 
       MakeFunc<Gribble>(ListNames.Gribbles);

The reason for this is that I have a helper class with a signature like this...

public void GetList<T>(ListNames listName, 
  Func<ObservableCollection<T>> serviceCall, 
  Action<ObservableCollection<T>> handleList)

serviceCall is the method that gets the list, and handleList is a callback method. At the moment, wherever this method is called, the code has to pass the actual function that gets the list.

However, this is proving to be a bad design choice, as it means that if two parts of the code both make a call to GetList for a particular list, they could pass in two different service calls, which will cause inconsistent results. I want to encapsulate the service call in the MakeFunc method, which would be called from GetList, meaning that the code that uses GetList never sees the actual service call, and so can't do anything wrong.

I have tried a few things, but am struggling to get anything that will compile. The closest I have got is the following...

public Func<ObservableCollection<T>> MakeFunc<T>(ListNames listName) {
  switch (listName) {
    case ListNames.Gribbles:
      return GetGribbles;
    case ListNames.Gribulators:
      return GenerateGribulators;
    case ListNames.Knepple:
      return MakeKnepples;
    default:
      throw new ArgumentException("Unknown list name");
  }
}

...but this gives a compiler errors along the lines of "GetGribbles() has the wrong return type" and the tooltip that pops up when I hover my mouse over GetGribbles in the MakeFunc method says

Expected a method with 'ObservableCollection<T> GetGribbles()' signature

Is it possible to do what I want? If so, anyone able to explain what I did wrong?

I'm using C# 4.0 in Visual Studio 2010 if it makes any difference.

Was it helpful?

Solution

Well if the Gribble, Gribulator, and Knepple classes share a common base type or implement a common interface, you can just do this:

public Func<ObservableCollection<ICommonInterface>> MakeFunc(ListNames listName) 
{
   ...
}

If they don't have a common base type or interface, you'd have to do this:

public Func<ICollection> MakeFunc(ListNames listName) 
{
   ...
}

Which, admittedly, is not a very good solution. Note: you can replace ICollection with INotifyCollectionChanged or whatever non-generic interface that you need most.

In both cases, you have to rely on the caller to specify the data type (even if the caller specifies the enum value as well). So, you could also get rid of the enum, and go for something like this:

public Func<ObservableCollection<T>> MakeFunc<T>() 
{
  if (typeof(T) == typeof(Gribble))
      return () => GetGribbles() as ObservableCollection<T>;
  if (typeof(T) == typeof(Gribulator))
      return () => GenerateGribulators() as ObservableCollection<T>;
  if (typeof(T) == typeof(Knepple))
      return () => MakeKnepples() as ObservableCollection<T>;
  throw new ArgumentException("Unknown list name");
}

Then the caller could simply write:

var gribblesFunc = MakeFunc<Gribble>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top