Void в C# генерики?


у меня есть универсальный метод, который принимает запрос и выдает ответ.

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

но мне не всегда нужен ответ на мой запрос, и я не всегда хочу подавать данные запроса, чтобы получить ответ. Я также не хочу копировать и вставлять методы полностью, чтобы внести незначительные изменения. То, что я хочу, это быть в состоянии сделать это:

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

возможно ли это каким-то образом? Кажется, что конкретно использование void не работает, но я надеюсь найти что-то похожее.

6 67

6 ответов:

вы не можете использовать void, но вы можете использовать object: Это небольшое неудобство, потому что ваш потенциальный -void функции должны возвращать null, но если он унифицирует ваш код, это должна быть небольшая цена.

это неспособность использовать void как тип возврата по крайней мере частично отвечает за разделение между Func<...> и Action<...> семьи общих делегатов: если бы можно было вернуться void, все Action<X,Y,Z> стало бы просто Func<X,Y,Z,void>. К сожалению, это невозможно.

нет, к сожалению, нет. Если void были "реальным" типом (например unit в F#, например) жизнь была бы намного проще во многих отношениях. В частности, нам не понадобятся оба Func<T> и Action<T> семьи - там просто будет Func<void> вместо Action,Func<T, void> вместо Action<T> etc.

кроме того, асинхронность проще - не было бы необходимости необщего Task тип вообще-мы бы просто Task<void>.

к сожалению, это не так, как работают системы типа C# или .NET...

вот что вы можете сделать. Как сказал @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

вы могли бы просто использовать Object как предлагали другие. Или Int32 который я видел некоторое использование. Используя Int32 вводит "фиктивный" номер (используйте 0), но, по крайней мере, вы не можете положить большой и экзотический объект в Int32 ссылка (структуры запечатаны).

вы также можете написать свой собственный тип "void":

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

MyVoid ссылки разрешены (это не статический класс), но может быть null. Конструктор экземпляра является частным (и если кто-то пытается вызовите этот частный конструктор через отражение, исключение будет брошено на них).

мне нравится идея Алексея Быкова выше, но ее можно было бы немного упростить

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

как я не вижу никаких видимых причин, почему ничего.AtAll не мог просто дать null

та же идея (или та, что у Jeppe Stig Nielsen) также отлично подходит для использования с типизированными классами.

например, если тип используется только для описания аргументов процедуры/функции, передаваемых в качестве аргумента некоторому методу, и сам он не принимает никаких аргументов.

(вы все равно нужно либо сделать фиктивную обертку, либо разрешить необязательное "ничего". Но ИМХО использование класса выглядит хорошо с myClass)

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

или

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

void, хотя типа, действует только в качестве возвращаемого типа метода.

и нет никакого способа обойти это ограничение void.