У меня есть общий метод, который принимает запрос и предоставляет ответ.
public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}
Но мне не всегда нужен ответ на свой запрос, и я не всегда хочу передавать данные запроса, чтобы получить ответ. Я также не хочу полностью копировать и вставлять методы для внесения незначительных изменений. Я хочу сделать это:
public Tre DoSomething<Tres>(Tres response)
{
return DoSomething<Tres, void>(response, null);
}
Возможно ли это каким-то образом? Кажется, что конкретно использование void не работает, но я надеюсь найти что-то аналогичное.
DoSomething(x);
вместоy = DoSomething(x);
Ответы:
Вы не можете использовать
void
, но можете использоватьobject
: это небольшое неудобство, потому что ваши потенциальныеvoid
функции должны возвращатьсяnull
, но если это унифицирует ваш код, это должна быть небольшая цена.Эта неспособность использовать
void
в качестве возвращаемого типа, по крайней мере, частично ответственна за разделение междуFunc<...>
иAction<...>
семействами универсальных делегатов: если бы можно было вернутьvoid
, всеAction<X,Y,Z>
стало бы простоFunc<X,Y,Z,void>
. К сожалению, это невозможно.источник
void
из этих бессмысленных методов с помощьюreturn System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(void));
. Но это будет пустота в коробке.void
в FP. И есть веские причины его использовать. В F #, все еще .NET, у нас естьunit
встроенные средства.Нет, к сожалению нет. Если бы
void
это был «настоящий» тип (например,unit
в F # ), жизнь была бы намного проще во многих отношениях. В частности, нам не нужны были быFunc<T>
иAction<T>
семьи и - простоFunc<void>
вместоAction
,Func<T, void>
вместоAction<T>
и т. Д.Это также упростило бы асинхронность - не было бы необходимости в неуниверсальном
Task
типе - у нас просто было быTask<void>
.К сожалению, системы типа C # или .NET работают иначе ...
источник
Unfortunately, that's not the way the C# or .NET type systems work...
Вы вселяли в меня надежду, что, возможно, в конечном итоге все так и будет. Означает ли ваш последний пункт, что у нас вряд ли когда-нибудь все будет так работать?Вот что ты можешь сделать. Как сказал @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
источник
Install-Package System.Reactive.Core
Kthx.Bye;
Вы можете просто использовать,
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
(когда тип может быть определен из контекста).источник
Мне нравится идея Алексея Быкова выше, но ее можно немного упростить
public sealed class Nothing { public static Nothing AtAll { get { return null; } } }
Поскольку я не вижу очевидной причины, почему Nothing.AtAll не может просто дать null
Та же идея (или идея Джеппе Стига Нильсена) также отлично подходит для использования с типизированными классами.
Например, если тип используется только для описания аргументов процедуры / функции, переданной в качестве аргумента некоторому методу, и сам по себе не принимает никаких аргументов.
(Вам все равно нужно будет создать фиктивную оболочку или разрешить необязательное «Nothing». Но, IMHO, использование класса выглядит хорошо с myClass <Nothing>)
void myProcWithNoArguments(Nothing Dummy){ myProcWithNoArguments(){ }
или
void myProcWithNoArguments(Nothing Dummy=null){ ... }
источник
null
имеет оттенок отсутствия или отсутствияobject
. Одно значениеNothing
означает, что оно никогда не будет похоже ни на что другое.Nothing
хранящимся в частном статическом поле и добавляющим частный конструктор. Тот факт, что null все еще возможен, раздражает, но это будет решено, надеюсь, с помощью C # 8.void
хотя и является типом, он действителен только как возвращаемый тип метода.Это ограничение невозможно обойти
void
.источник
В настоящее время я создаю собственные запечатанные типы с помощью частного конструктора. Это лучше, чем бросать исключения в c-tor, потому что вам не нужно дойти до времени выполнения, чтобы понять, что ситуация неверна. Это немного лучше, чем возврат статического экземпляра, потому что вам не нужно выделять ни разу. Это немного лучше, чем возврат статического нуля, потому что он менее подробен на стороне вызова. Единственное, что может сделать вызывающий - дать null.
public sealed class Void { private Void() { } } public sealed class None { private None() { } }
источник