[c#] C # 제네릭에서 무효?

요청을 받고 응답을 제공하는 일반적인 메서드가 있습니다.

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

하지만 항상 내 요청에 대한 응답을 원하지는 않으며 응답을 받기 위해 요청 데이터를 제공하고 싶지는 않습니다. 또한 사소한 변경을 위해 메서드 전체를 복사하고 붙여 넣을 필요가 없습니다. 내가 원하는 것은 다음과 같이 할 수있는 것입니다.

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

어떤 식 으로든 이것이 가능합니까? 구체적으로 void를 사용하는 것이 작동하지 않는 것 같지만 비슷한 것을 찾고 싶습니다.



답변

을 사용할 수는 없지만 사용할 void수 있습니다 object. void함수가 반환되어야 하므로 약간 불편 null하지만 코드를 통합하면 지불하는 데 약간의 비용이 듭니다.

void반환 유형 으로 사용할 수없는이 무능력 은 적어도 부분적으로 Func<...>와 사이의 분할에 대한 책임이 있습니다.Action<...> 은 제네릭 대리자 패밀리 이 있습니다. 반환이 가능 했다면 void모든 Action<X,Y,Z>것이 단순히 Func<X,Y,Z,void>. 불행히도 이것은 불가능합니다.


답변

아니요, 안타깝게도 아닙니다. 경우 void“진짜”형이었다 (같은 unitF #의는 , 예를 들어) 생활은 여러 가지면에서 훨씬 간단 할 것이다. 특히, 우리는 모두 필요가 없을 것입니다 Func<T>Action<T>그냥 거기있을 거라고 – 가족을 Func<void>대신 Action, Func<T, void>대신 Action<T>

또한 비동기식을 더 간단하게 만들 수 있습니다. 비 제네릭 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. 인스턴스 생성자는 비공개입니다 (누군가 리플렉션을 통해이 비공개 생성자를 호출하려고하면 예외가 발생합니다).


값 튜플 (2017, .NET 4.7)이 도입되었으므로 이러한 .NET Framework 대신 구조체ValueTuple (0- 튜플, 비 제네릭 변형) 를 사용 하는 것이 당연 할 수 있습니다 MyVoid. 인스턴스에는를 ToString()반환 "()"하는가 있으므로 제로 튜플처럼 보입니다. 현재 버전의 C #에서는 ()코드 의 토큰 을 사용하여 인스턴스를 가져올 수 없습니다 . 대신 default(ValueTuple)또는 default(문맥에서 유형을 유추 할 수있는 경우) 사용할 수 있습니다.


답변

위의 Aleksey Bykov의 아이디어가 마음에 들지만 약간 단순화 할 수 있습니다.

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

Nothing.AtAll이 null을 줄 수없는 명백한 이유가없는 것처럼

동일한 아이디어 (또는 Jeppe Stig Nielsen의 아이디어)도 형식화 된 클래스와 함께 사용하기에 좋습니다.

예를 들어 형식이 일부 메서드에 인수로 전달 된 프로 시저 / 함수에 대한 인수를 설명하는 데만 사용되며 자체적으로 인수를 사용하지 않는 경우입니다.

(그래도 더미 래퍼를 만들거나 선택적인 “Nothing”을 허용해야합니다. 그러나 IMHO 클래스 사용은 myClass <Nothing>으로 멋지게 보입니다.)

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

또는

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


답변

void유형이지만 메서드의 반환 유형으로 만 유효합니다.

이 제한을 피할 방법은 없습니다 void.


답변

현재 내가하는 일은 개인 생성자로 사용자 지정 봉인 된 형식을 만드는 것입니다. 상황이 올바르지 않은지 확인하기 위해 런타임까지 얻을 필요가 없기 때문에 c-tor에서 예외를 던지는 것보다 낫습니다. 한 번도 할당 할 필요가 없기 때문에 정적 인스턴스를 반환하는 것보다 미묘하게 낫습니다. 호출 측에서 덜 장황하기 때문에 정적 null을 반환하는 것보다 미묘하게 낫습니다. 호출자가 할 수있는 유일한 일은 null을주는 것입니다.

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

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