114

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

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

但我并不总是希望我的请求得到响应,我也不总是希望提供请求数据来获得响应。我也不想复制和粘贴整个方法来进行细微的更改。我想要的是能够做到这一点:

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

这在某种程度上可行吗?似乎专门使用 void 不起作用,但我希望找到类似的东西。

4

7 回答 7

115

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

这种无法void用作返回类型的原因至少部分地导致了泛型委托Func<...>Action<...>家族之间的分裂:如果可以返回void,那么一切Action<X,Y,Z>都会变得简单Func<X,Y,Z,void>。不幸的是,这是不可能的。

于 2012-07-03T20:53:40.147 回答
93

不,很遗憾没有。如果void是“真实”类型(例如unit在 F#中),那么生活在许多方面都会简单得多。特别是,我们不会同时需要Func<T>Action<T>家庭——只需要Func<void>代替ActionFunc<T, void>代替Action<T>等。

它还会使 async 更简单——根本不需要非泛型Task类型——我们只需要Task<void>.

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

于 2012-07-03T20:54:55.420 回答
29

这是你可以做的。正如@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;
}

或者使用 Rx 团队已经制作的东西:http: //msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx

于 2013-09-26T17:15:25.387 回答
17

您可以Object像其他人建议的那样简单地使用。或者Int32我已经看到了一些用途。usingInt32引入了一个“虚拟”数字( use 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)or just default(当类型可以从上下文中推断出来时) 代替。

于 2012-07-03T21:19:58.720 回答
8

我喜欢上面 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){
    ...
}
于 2015-06-15T19:42:21.470 回答
4

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

没有办法绕过这个限制void

于 2012-07-03T20:52:14.987 回答
1

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

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

public sealed class None {
    private None() { }
}
于 2019-11-12T11:51:44.073 回答