2014-09-04 3 views
1

변경 가능한 유형에 추가 :내가 양식에 객체를 짓고 있어요

return table.Rows.Cast<DataRow>() 
    .Select(row => new Something 
    { 
    Field = row["field1"] as int?, 
    Bunch = GetBunch(index) 
    }); 

GetBunch() 다음으로.

예상대로 작동합니다. 이제 우리는 배열에 추가 요소를 추가해야한다는 것을 알게되었습니다. 여러 가지 이유로 인해 메소드의 시그니처를 변경하는 옵션이 아니며 내부에 추가 요소를 추가하는 것도 가능하지 않습니다.

나는과 같이 추가 말았을 추가하려고 :

return table.Rows.Cast<DataRow>() 
    .Select(row => new Something 
    { 
    Field = row["field1"] as int?, 
    Bunch = GetBunch(index).Add(new Thingy() { ... }) 
    }); 

하지만 추가가() 거기에 새로운 요소와 함께 원래의 배열을 반환하지 않기 때문에 그것은 작동하지 않았다. int을 반환합니다. 원래 개체가 불변 일 경우, Add()의 결과는 내가 원했던 것이지만 분명히 그렇지 않습니다.

가변 개체를 immutabilize 수 있습니까? 그렇지 않다면 (나는 그것이 확실하지 않기 때문에), 어떻게하면 쉽게 처리 할 수 ​​있습니까? (쉽게 = 생성 된 것을 저장하지 않고 액세스하고 번 배열에 속성 배열을 추가하면됩니다.

NB의 경우 결과의 순서는 중요하지 않습니다. 적절한 유형은 어떤 종류의 가방 일 것이지만 나는 기존 디자인으로 손으로 묶었습니다. 이 아마도 같은

+4

나는 가변성과 불변성 여기 정말 중요하다는 것을 확실하지 않다. 나는 당신이 어디에서 불변의 객체를 가지고 왔는지를 본다. 그리고 아이템을 추가하는 것은 필연적으로 새로운 객체를 반환하는 것을 포함 할 것이지만, 그것은이 동작이 변경 불가능한 객체에 의해서만 사용된다는 것을 의미하지는 않는다. 메소드 호출에서 자신을 반환 한 객체를 쉽게 만들 수 있습니다. 이것은 문제를 푸는 데 분명히 유용하지는 않지만, 변경 가능한 객체를 불변으로 만들고 싶다는 모든 이야기는 질문을 읽을 때 혼란 스럽습니다. – Chris

답변

5

뭔가 :

return table.Rows.Cast<DataRow>() 
.Select(row => { 
        var list = GetBunch(index); 
        list.Add(new Thingy() { ... }); 
        return new SomeThing 
         { 
          Field = row["field1"] as int?, 
          Bunch = list 
         }; 
       }); 

는 @ 크리스는 람다 문을 사용할 수 있습니다 코멘트에서 언급 한 바와 같이, 당신은 반드시 당신이 내부에 원하는대로 할 수있는 람다 expression.You를 사용할 필요가 없습니다 블록은 DataRow을 사용하고 SomeThing을 반환하는 메서드이기 때문에 좋은 Selman22의 대답에

+1

여기서 중요한 것은 람다가 코드 블록을 가질 수 있으며 단일 항목을 본체로 가질 수 없다는 것입니다. – Chris

+0

@Chris 예. 이것은 람다 식 –

+0

+1이 아니라 lamda 문이라고합니다. 일회성 사례가있는 경우 헬퍼 메소드로 리팩토링하는 것보다 코드에서 여러 번 반복되는 경우이 방법을 사용하는 것이 좋습니다. 나는. 내 답변에 포함 된 "이 목록에 항목 추가"또는 더 많은 것을 추가하는 도우미로'GetBunch'를 래핑하는 것으로 확장합니다. –

2

대안 : 도우미 확장 메서드를 만들려면 람다 인라인에 포장 할 필요없이 GetBunch()의 결과에 추가 할 것 :

static class MyListExtenstions 
{ 
    static IList AddToList<T>(this IList list, T item) 
    { 
    list.Add(item); 
    return list; 
    } 
} 

을 그리고 인라인을 사용

return table.Rows.Cast<DataRow>() 
    .Select(row => new Something 
    { 
     Field = row["field1"] as int?, 
     Bunch = GetBunch(index).AddToList(new Thingy() { ... }) 
    }); 

더 많은 중간 개체를 만드는 LINQ 방식이 하나 더 있지만 불변 (항목 추가가 예외를 throw 함을 의미 함)에서 작동합니다. 목록 :

체인 연결에 사용할 수있는 방법을 원할 경우 IEnumerable<T>.Concat() (그리고 귀하의 경우에는 .ToList())을 사용할 수 있습니다. 이 방법은 당신에게 새로운 목록을 제공하고 GetBunch의 결과는 경우에 유용 할 것 :

GetBunch(index) 
    .Concat(Enumerable.Repeat(new Thingy() { ... }, 1)) 
    .ToList() 

참고 : 당신의 GetBunch 제네릭 IList<T> 또는 IEnumerable<T>을 반환 경우 Enumerable (같은이 .Concat())의 헬퍼 방법을 사용할 수 있습니다보다.비 제네릭 버전을 반환하기 때문에 Enumerable.Cast과 같은 일반 변형으로 변환하거나 LINQ 방식을 사용하기 위해 제네릭 인터페이스로 캐스팅해야합니다. 실제 유형이 무엇인지 또는 어떤 유형의 상품이 반환되어야 하는지를 알아야합니다.

GetBunch(index).Cast<object>() 
GetBunch(index) as IList<Thingy> 
+0

+1이 또한 좋은 생각입니다. –

+0

이상한. 나는 인텔리 센스에서 * Concat * * Union *을 얻지 못한다. 내가 IList *를 사용하고 있기 때문에 그런가? 그럴리가 없어, 그렇지? –

+1

@ KonradViltersten - 주석에 대한 답을 인라인했습니다. 실제로는 대부분의 LINQ 메서드를 사용할 수 없도록하는 비표준 IList를가집니다. –

0
return table.Rows.Cast<DataRow>() 
    .Select(row => new Something 
    { 
     Field = row["field1"] as int?, 
     Bunch = GetBunch(index).Union(x => 
      new[] { new Thingy() { ... } } 
      ).ToList() 
    }); 
+0

'Union '이 설정되어 주문을 보장하지 않습니다. 'Concat'은 가장 일반적인 경우에 더 낫습니다 (답안의 샘플). –

+0

@AlexeiLevenkov 사실, 여기에는 문제가 없습니다. 그러나, 나는 나의 다른 코멘트에서 언급했듯이, 여기에 인텔리 센스 (Intellisense)로부터 연합 *을 얻지 못한다. 정말로 이상한. –

+0

@ KonradViltersten -이 대답을 사용할 수 있도록 "중요하지 않은 순서"주석으로 게시물을 업데이트하는 것도 고려하십시오. –

관련 문제