Fenchurch
Fenchurch

Reputation: 303

A single generic solution?

I want to write a generic method along the following lines:

public IEnumerable<T> S<T> (List<T> source)
{
    //dosomething with source
    if (someCondition)
        yield return null;
    else
        yield return someNonNullItem;
}

T can be a value type (e.g. int), a nullable type (e.g. int?), or a ref type (e.g. string). In all the three cases, I want to have the ability to return a null value.

The //dosomething block is pretty generic, involves shifting things around, and can be used with all types with no modification. Similarly, the (someCondition) boolean check does not have any type dependency.

Some considerations:

  1. I cannot use default(T) where T is a non-nullable value type (e.g. default(T) where T is int won't work). An explicit representation of null is required.
  2. I don't want to convert from T to T? if I can avoid it since the source list can be quite long (millions of items).

At present, I'm stuck with having to write three functions, and one of them has to have a different name (because the type constraints are not deemed part of the method signature). The three functions have identical bodies (not shown for brevity).

    public IEnumerable<T?> S<T>(List <T> source) where T:struct
    {
    }

    public IEnumerable<T?> S<T>(List <T?> source) where T : struct
    {
    }

    public IEnumerable<T> S4Ref<T>(List <T> source) where T : class
    {
    }

In the first two methods, I need the T:struct constraint to be able to return the Nullable. In the third method: (a) I need a new name, S4Ref, to avoid clashing with the first method, and, (b) I need the T:class constraint to be able to return a null.

In reality, there are numerous such S methods I have to write, and if I follow the above approach, I'll have to write three versions for each of them. I'll also turn them into extension methods for List

Questions:

  1. Is there a way to have a single generic function that does this? Or at least reduce from 3 to 2 methods?
  2. If not, what is the best way to eliminate duplication in the function bodies?

At present I'm veering towards using T4 templates to address this.

Upvotes: 3

Views: 160

Answers (1)

KC-NH
KC-NH

Reputation: 748

You've set yourself up with conflicting constraints. In the problem definition, you say you want a function that works on value types (i.e. int) but be able to return null without turning it into a nullable type. As a design paradigm, I don't expect a collection of things to include something that doesn't exist. Yeah, I said that. To me, returning a null item means it doesn't exist, and yet you are returning null. If the purpose of function S is to filter items, it would be better to skip the item that doesn't match and return the next one.

For example, a typical use of IEnumerable is code that looks like this:

    List<int> myList = ....  // somehow fill the list
    foreach(int element in S(myList))
    {
         // do something with the int element.  What should I expect to do with a null
         // even if you could return one?  The only thing I could reasonable do here is
         // skip it.  I have no idea which element of myList the null corresponds to

    }

in other words, even if the foreach look like this:

    foreach(int? element in S(myList))

I'm still stuck as to what to do with a null value for element. There is still no context to know which element of myList caused a null from function S.

Upvotes: 0

Related Questions