void in C# generics?

我有一个接受请求并提供响应的通用方法。

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.

58518 次浏览

void虽然是一种类型,但只作为方法的返回类型有效。

没有办法绕过 void的这个限制。

您不能使用 void,但是您可以使用 object: 这有点不方便,因为您想要使用的 void函数需要返回 null,但是如果它统一了您的代码,那么它应该是一个很小的代价。

这种不能使用 void作为返回类型的情况至少部分地导致了通用委托的 Func<...>Action<...>系列之间的分裂: 如果有可能返回 void,所有的 Action<X,Y,Z>将变成简单的 Func<X,Y,Z,void>。不幸的是,这是不可能的。

不,很不幸没有。如果 void是一种“真正的”类型(例如 F # 的 unit) ,生活在许多方面会简单得多。特别是,我们不需要 Func<T>Action<T>两个家族-只需要 Func<void>而不是 ActionFunc<T, void>而不是 Action<T>等等。

它还会使异步变得更简单——根本不需要非通用的 Task类型——我们只需要 Task<void>

不幸的是,这不是 C # 或.NET 类型系统的工作方式..。

您可以像其他人建议的那样简单地使用 Object。或者 Int32,我看到了一些用途。使用 Int32引入了一个“虚拟”数字(使用 0) ,但是至少您不能将任何大的和奇异的对象放入 Int32引用中(结构是密封的)。

你也可以写你自己的“ void”类型:

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

允许 MyVoid引用(它不是静态类) ,但只能是 null。实例构造函数是私有的(如果有人试图通过反射调用这个私有构造函数,就会抛出异常)。


自从引入值元组以来(2017,。NET 4.7) ,使用 结构 ValueTuple(0元组,非泛型变体)代替这样的 MyVoid也许是很自然的。它的实例有一个返回 "()"ToString(),所以它看起来像一个零元组。在 C # 的当前版本中,您不能使用代码中的标记 ()来获取实例。您可以使用 default(ValueTuple)或者仅仅使用 default(当可以从上下文推断类型时)。

正如@JohnSkeet 所说,C # 中没有单元类型,所以你可以自己创建它!

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

现在您总是可以使用 Func<..., ThankYou>而不是 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

我喜欢上面 Aleksey Bykov 的想法,但是它可以简化一点

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

因为我看不出为什么 Nothing. AtAll 不能给 null

同样的想法(或 Jeppe Stig Nielsen 的想法)也适用于类型化类。

例如,如果该类型仅用于描述作为参数传递给某个方法的过程/函数的参数,并且它本身不接受任何参数。

(您仍然需要制作一个虚拟包装器,或者允许一个可选的“ Nothing”。但恕我直言,myClass < Nothing > 的类用法看起来不错

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

或者

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

我当前所做的是使用私有构造函数创建自定义密封类型。这比在 c-tor 中抛出异常要好,因为您不必等到运行时才能发现情况是不正确的。这比返回静态实例稍微好一些,因为您甚至不需要分配一次。它比返回 static null 稍微好一些,因为它在调用端不那么冗长。调用者唯一能做的就是赋值 null。

public sealed class Void {
private Void() { }
}


public sealed class None {
private None() { }
}