Home » c# » void in C# generics?

void in C# generics?

Posted by: admin November 29, 2017 Leave a comment

Questions:

I have a generic method that takes a request and provides a response.

public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}

But I don’t always want a response for my request, and I don’t always want to feed request data to get a response. I also don’t want to have to copy and paste methods in their entirety to make minor changes. What I want, is to be able to do this:

public Tre DoSomething<Tres>(Tres response)
{
    return DoSomething<Tres, void>(response, null);
}

Is this feasible in some manner? It seems that specifically using void doesn’t work, but I’m hoping to find something analogous.

Answers:

You cannot use void, but you can use object: it is a little inconvenience because your would-be-void functions need to return null, but if it unifies your code, it should be a small price to pay.

This inability to use void as a return type is at least partially responsible for a split between the Func<...> and Action<...> families of generic delegates: had it been possible to return void, all Action<X,Y,Z> would become simply Func<X,Y,Z,void>. Unfortunately, this is not possible.

Questions:
Answers:

No, unfortunately not. If void were a “real” type (like unit in F#, for example) life would be a lot simpler in many ways. In particular, we wouldn’t need both the Func<T> and Action<T> families – there’d just be Func<void> instead of Action, Func<T, void> instead of Action<T> etc.

It would also make async simpler – there’d be no need for the non-generic Task type at all – we’d just have Task<void>.

Unfortunately, that’s not the way the C# or .NET type systems work…

Questions:
Answers:

Here is what you can do. As @JohnSkeet said there is no unit type in C#, so make it yourself!

public sealed class ThankYou {
   private ThankYou() { }
   private readonly static ThankYou bye = new ThankYou();
   public static ThankYou Bye { get { return bye; } }
}

Now you can always use Func<..., ThankYou> instead of Action<...>

public ThankYou MethodWithNoResult() {
   /* do things */
   return ThankYou.Bye;
}

Or use something already made by the Rx team: http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx

Questions:
Answers:

You could simply use Object as others have suggested. Or Int32 which I have seen some use. Using Int32 introduces a “dummy” number (use 0), but at least you can’t put any big and exotic object into an Int32 reference (structs are sealed).

You could also write you own “void” type:

public sealed class MyVoid
{
  MyVoid()
  {
    throw new InvalidOperationException("Don't instantiate MyVoid.");
  }
}

MyVoid references are allowed (it’s not a static class) but can only be null. The instance constructor is private (and if someone tries to call this private constructor through reflection, an exception will be thrown at them).

Questions:
Answers:

void, though a type, is only valid as a return type of a method.

There is no way around this limitation of void.

Questions:
Answers:

I like the idea by Aleksey Bykov above, but it could be simplified a bit

public sealed class Nothing {
    public static Nothing AtAll { get { return null; } }
}

As I see no apparent reason why Nothing.AtAll could not just give null

The same idea (or the one by Jeppe Stig Nielsen) is also great for usage with typed classes.

E.g. if the type is only used to describe the arguments to a procedure/function passed as an argument to some method, and it itself does not take any arguments.

(You will still need to either make a dummy wrapper or to allow an optional “Nothing”. But IMHO the class usage looks nice with myClass<Nothing> )

void myProcWithNoArguments(Nothing Dummy){
     myProcWithNoArguments(){
}

or

void myProcWithNoArguments(Nothing Dummy=null){
    ...
}