Void в С# generics?
У меня есть общий метод, который принимает запрос и предоставляет ответ.
public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}
Но мне не всегда нужен ответ для моего запроса, и я не всегда хочу подавать данные запроса, чтобы получить ответ. Я также не хочу копировать и вставлять методы полностью, чтобы внести незначительные изменения. Я хочу, чтобы это можно было сделать:
public Tre DoSomething<Tres>(Tres response)
{
return DoSomething<Tres, void>(response, null);
}
Насколько это возможно? Похоже, что конкретное использование void не работает, но я надеюсь найти что-то аналогичное.
Ответы
Ответ 1
Вы не можете использовать void
, но можете использовать object
: это немного неудобно, потому что ваши функции be-be- void
должны возвращать null
, но если он унифицирует ваш код, он должен быть небольшая цена для оплаты.
Эта неспособность использовать void
как возвращаемый тип, по меньшей мере, частично отвечает за разделение между семействами Func<...>
и Action<...>
общих делегатов: было ли возможно вернуть void
, all Action<X,Y,Z>
станет просто Func<X,Y,Z,void>
. К сожалению, это невозможно.
Ответ 2
Нет, к сожалению нет. Если бы void
были "реальным" типом (например, unit
в F #), жизнь была бы намного проще во многих отношениях. В частности, нам не нужны семейства Func<T>
и Action<T>
- вместо Action
, Func<T, void>
вместо Action<T>
и т.д. Вместо Action<T>
и т.д. Вместо Func<void>
.
Это также упростит асинхронность - вообще не будет необходимости в универсальном типе Task
- у нас будет только Task<void>
.
К сожалению, это не так, как работают системы типа С# или .NET.
Ответ 3
Вот что вы можете сделать. Как сказал @JohnSkeet, в С# нет типа юнитов, так что сделайте это сами!
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
Ответ 4
Вы можете просто использовать Object
, как предлагали другие. Или Int32
, который я видел некоторое использование. Использование Int32
вводит "фиктивное" число (используйте 0
), но, по крайней мере, вы не можете поместить большой и экзотический объект в ссылку Int32
(структуры запечатаны).
Вы также можете написать свой собственный тип void:
public sealed class MyVoid
{
MyVoid()
{
throw new InvalidOperationException("Don't instantiate MyVoid.");
}
}
Ссылки MyVoid
разрешены (это не статический класс), но могут быть только null
. Конструктор экземпляра является закрытым (и если кто-то попытается вызвать этот закрытый конструктор с помощью отражения, в них будет выдано исключение).
Поскольку были введены кортежи значений (2017,.NET 4.7), может быть естественным использовать struct ValueTuple
(0-кортеж, неуниверсальный вариант) вместо такого MyVoid
. Его экземпляр имеет ToString()
, который возвращает "()"
, поэтому он выглядит как нулевой кортеж. Начиная с текущей версии С#, вы не можете использовать токены ()
в коде для получения экземпляра. Вместо этого вы можете использовать default(ValueTuple)
или просто default
(когда тип может быть выведен из контекста).
Ответ 5
Мне нравится идея Алексея Быкова выше, но она может быть упрощена немного
public sealed class Nothing {
public static Nothing AtAll { get { return null; } }
}
Поскольку я не вижу никакой очевидной причины, почему Nothing.AtAllAllAllAll не может просто дать null
То же самое (или Jeppe Stig Nielsen) также отлично подходит для использования с типизированными классами.
например. если тип используется только для описания аргументов процедуры/функции, переданных в качестве аргумента для некоторого метода, и сам он не принимает никаких аргументов.
(Вам все равно нужно либо сделать фиктивную оболочку, либо разрешить необязательное "Nothing". Но IMHO использование класса выглядит красиво с myClass <Nothing> )
void myProcWithNoArguments(Nothing Dummy){
myProcWithNoArguments(){
}
или
void myProcWithNoArguments(Nothing Dummy=null){
...
}
Ответ 6
void
, хотя тип, действителен только как возвращаемый тип метода.
Нет ограничений по этому ограничению void
.