태그 보관물: lambda

lambda

C # 람다를 선언하고 즉시 호출하는 방법이 있습니까? 제한적입니다), 작성하고 싶습니다 var

람다 함수를 선언하고 즉시 호출 할 수 있습니다.

Func<int, int> lambda = (input) => { return 1; };
int output = lambda(0);

한 줄로 할 수 있는지 궁금합니다.

int output = (input) => { return 1; }(0);

컴파일러 오류 “방법 이름 예상”을 제공합니다. 전송 Func<int, int>이 작동하지 않습니다.

int output = (Func<int, int>)((input) => { return 1; })(0);

동일한 오류가 발생하며 아래에 언급 된 이유로 입력 인수 유형 (첫 번째 int) 을 명시 적으로 지정하지 않아도됩니다 .


예를 들어 코드를 직접 삽입하는 대신 내가 이것을하고 싶은지 궁금 할 것입니다 int output = 1;. 이유는 다음과 같습니다.로 SOAP 웹 서비스에 대한 참조를 svcutil생성했습니다. 그래서 대신

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order == null ? new Shipment[0]
        o.Shipment_Order.Select(sh => new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = CreateAddress(sh.ReceiverAddress_Shipment);
        }).ToArray()
};

별도의 CreateAddress(GetOrderResultOrderShipment_OrderShipmentShipment_Address address)방법 (실제 이름은 더 길고 양식에 대한 제어가 매우 제한적입니다), 작성하고 싶습니다

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order == null ? new Shipment[0]
        o.Shipment_Order.Select(sh => new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = sh.ReceiverAddress_Shipment == null ? null : () => {
                var a = sh.ReceiverAddress_Shipment.Address;
                return new Address {
                    Street = a.Street
                    ...
                };
            }()
        }).ToArray()
};

내가 쓸 수 있다는 것을 안다

Address = sh.ReceiverAddress_Shipment == null ? null : new Address {
    Street = sh.ReceiverAddress_Shipment.Address.Street,
    ...
}

그러나 sh.ReceiverAddress_Shipment.Address필드가 많으면 그 부분 조차 매우 반복적입니다. 람다를 선언하고 즉시 호출하면 문자를 쓰는 것이 더 우아 합니다.



답변

람다를 캐스팅하는 대신 작은 도우미 함수를 사용하는 것이 좋습니다.

public static TOut Exec<TIn, TOut>(Func<TIn, TOut> func, TIn input) => func(input);

다음과 같이 사용할 수 있습니다 int x = Exec(myVar => myVar + 2, 0);.. 이것은 여기에 제안 된 대안보다 훨씬 좋습니다.


답변

추악하지만 가능합니다.

int output = ((Func<int, int>)(input => { return 1; }))(0);

캐스트 할 수 있지만 람다는 괄호로 묶어야합니다.

위의 내용도 단순화 할 수 있습니다.

int output = ((Func<int, int>)(input => 1))(0);

답변

C #의 Lambda 리터럴은 그 의미가 유형에 따라 다르다는 점에서 호기심이 있습니다. 그들은 반환 유형에 본질적으로 과부하 되어 C #의 다른 곳에는 존재하지 않습니다. (숫자 리터럴은 다소 유사합니다.)

동일한 람다 리터럴을 수행 할 수 있습니다 중 하나를 당신이 실행할 수있는 익명 함수 (즉,로 평가 Func/ Action) 또는 종류 (즉, LINQ 표현 나무)는 추상 구문 트리 등으로, 몸의 내부 운영의 추상적 인 표현입니다.

후자는 예를 들어 LINQ to SQL, LINQ to XML 등의 작동 방식입니다. 람다 실행 코드로 평가 하지 않고 LINQ Expression Tree로 평가 한 다음 LINQ 공급자는 해당 Expression Tree를 사용하여 람다의 본문은 수행하고 예를 들어 SQL 쿼리를 생성합니다.

귀하의 경우 컴파일러가 람다 리터럴이 FuncLINQ 식 으로 평가되는 것을 알 수있는 방법이 없습니다 . Johnathan Barclay의 답변이 작동하는 이유 는 람다 식에 유형을 제공하므로 컴파일러는 내부 코드 를 나타내는 평가되지 않은 LINQ 식 트리 대신 람다의 본문 Func실행 하는 컴파일 된 코드를 원한다는 것을 알고 있습니다. 람다의 몸.


답변

당신은의 선언을 인라인 수 Func수행하여

int output = (new Func<int, int>(() => { return 1; }))(0);

즉시 호출합니다.


답변

Select메소드 에서 별명을 작성할 수도 있습니다.

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order == null ? new Shipment[0]
        o.Shipment_Order.Select(sh => {
          var s = sh.ReceiverAddress_Shipment;
          var a = s.Address;
          return new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = s == null ?
                      null :
                      new Address {
                        Street = a.Street
                        ...
                      }
          };
        }).ToArray()
};

또는 ??운영자 와

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order?.Select(sh => {
        var s = sh.ReceiverAddress_Shipment;
        var a = s.Address;
        return new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = s == null ?
                      null :
                      new Address {
                          Street = a.Street
                          ...
                      }
        };
    }).ToArray() ?? new Shipment[0]
};

답변

확장 방법 설계 지침 몇 가지를 위반하지 않는다면 null 조건부 연산자와 결합 된 확장 방법 ?.을 사용하면 합리적으로 멀리 갈 수 있습니다.

public static class Extensions
{
    public static TOut Map<TIn, TOut>(this TIn value, Func<TIn, TOut> map)
        where TIn : class
        => value == null ? default(TOut) : map(value);

    public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> items)
        => items ?? Enumerable.Empty<T>();
}

당신에게 이것을 줄 것입니다 :

return new Order
{
    OrderDate = o.OrderDate,
    Shipments = o.Shipment_Order.OrEmpty().Select(sh => new Shipment
    {
        ShipmentID = sh.ShipmentID,
        Address = sh.ReceiverAddress_Shipment?.Address.Map(a => new Address
        {
            Street = a.Street
        })
    }).ToArray()
};

대부분 배열이 필요한 경우 ToArray확장 메서드를 재정 의하여 몇 가지 메서드 호출을 캡슐화하십시오.

public static TOut[] ToArray<TIn, TOut>(this IEnumerable<TIn> items, Func<TIn, TOut> map)
    => items == null ? new TOut[0] : items.Select(map).ToArray();

를 야기하는:

return new Order
{
    OrderDate = o.OrderDate,
    Shipments = o.Shipment_Order.ToArray(sh => new Shipment
    {
        ShipmentID = sh.ShipmentID,
        Address = sh.ReceiverAddress_Shipment?.Address.Map(a => new Address
        {
            Street = a.Street
        })
    })
};

답변