2009-03-07 2 views
1

내가 본 방법 :참조 형식 매개 변수를 잘못 수정하는 메서드입니까? 이 같은

public void Foo(List<string> list) 
{ 
    list.Add("Bar"); 
} 

방법에 매개 변수를 수정하려면이 좋은 방법인가?

더 좋지 않습니까?

public List<string> Foo(List<string> list) 
{ 
    // Edit 
    List<string> newlist = new List<string>(list); 
    newlist.Add("Bar"); 
    return newlist; 
} 

예기치 않은 부작용이있는 것처럼 느껴집니다.

+0

나는 당신이 말하는 것을 의미한다고 생각한다 목록 새로운 목록 = 새로운 목록 (목록); –

+0

감사합니다. 나는 그것을 업데이트했다. –

답변

7

예를 들어, 첫 번째는 두 번째 것보다 훨씬 나을 것 같습니다. 목록을 수락하고 목록을 반환하는 메서드를 본다면 내 첫 번째 가정은 새 목록을 반환하고 부여 된 메서드를 건드리지 않는 것입니다. 따라서 두 번째 방법은 예기치 않은 부작용이있는 방법입니다.

메서드 이름이 적절하면 매개 변수를 수정할 위험이 거의 없습니다. 이것을 생각해보십시오 :

public void Fill<T>(IList<T> list) 
{ 
    // add a bunch of items to list 
} 

"채우기"와 같은 이름을 사용하면 메서드가 목록을 수정한다는 것을 확실히 알 수 있습니다.

+0

두 번째 방법에서 매개 변수를 변경하지 않도록 편집 한 질문입니다. –

+0

내가 가진 문제는 매개 변수를 수정하지 않는 방법을 기대하는 습관이 있다는 것입니다. 내가 어떻게 그 습관에 빠졌는지 모르겠다. –

+0

당신은 F #을 조사해야합니다. 기능 프로그래밍이 당신의 골목 바로 위에있을 것 같은 소리. –

0

두 방법 모두에서 똑같은 일을하고 있습니다. 둘 중 하나만 동일한 목록을 반환합니다.

정말 내 의견으로는 당신이하는 일에 달려 있습니다. 그냥 무슨 일이 벌어지고 있는지에 대한 문서가 확실한 지 확인하십시오. 당신이 그런 종류의 일에 있다면 사전 조건과 사후 조건을 적어 라.

+0

두 번째 방법에서 매개 변수를 변경하지 않도록 편집 한 질문입니다. –

1

솔직히이 경우 두 가지 방법 모두 다소 차이가 없습니다. 모두에서 전달 된 List을 수정한다.

목적은 이러한 방법에 의해 불변의 목록을 가지고 있으면, 두 번째 예에서 전송 된 List의 복사본을 만들고, 그런 다음에 Add 작업을 수행해야 새 List을 입력 한 다음 반환하십시오.

public List<string> Foo(List<string> list) 
{ 
    List<string> newList = (List<string>)list.Clone(); 
    newList.Add("Bar"); 
    return newList; 
} 

이 방법은 Foo 방법은 새로 List을 만들어 반환 얻을 것이다 호출 방법 : 내 생각 엔의 라인을 따라 뭔가 될 수 있도록

나는, C 번호 나 .NET에 익숙하지 않은 해요 전달 된 원본 List은 건드리지 않았습니다.

이것은 실제로 사양 또는 API의 "계약"에 달려 있습니다. 따라서 List을 수정할 수있는 경우 첫 번째 방법으로 문제가 발생하지 않습니다.

0

확장 방법의 출현으로 인해 부작용이있는 메소드를 다루는 것이 더 쉬워졌습니다. 예를 들어, 예제는

public static class Extensions 
{ 
    public static void AddBar(this List<string> list) 
    { 
    list.Add("Bar"); 
    } 
} 

말 뭔가가 목록에 무슨 일이 일어나고 있는지가 명확하게

mylist.AddBar(); 

로 전화를 훨씬 더 직관적된다.

의견에서 언급했듯이 목록 수정은 혼란 스러울 수 있으므로 목록에서 가장 유용합니다. 간단한 객체에서, 나는 장소에서 객체를 수정하는 경향이 있습니다.

+0

이것은 실제 질문에 답하는 것처럼 보입니다. 즉, 첫 번째 스타일은 Foo 메서드가 전달 된 매개 변수를 변경한다는 것을 한눈에 알지 못한다는 점에서 문제가 있습니다. 그러나 클래스를 작성하는 아이디어는 목록에 추가/변경하려는 모든 가치가 미친 것입니다. – Mike

+0

나는 일반 액세스와 달리 목록의 관점에서 특별히 생각하고있었습니다. 내 주니어 개발자는 목록에서 부작용이 생기는 경우가 많습니다. 말하자면, 읽기 전용 속성과 설정 메서드를 사용하는 것이 좋습니다. –

0

실제로 매개 변수로 목록을 사용하는 메서드가 목록을 수정한다는 것은 예상치 못한 일은 아닙니다. 당신은 또한 목록을 변경을하는 방법을 금지하지 않는 다음과 같은 인터페이스를 사용하여

public int GetLongest(IEnumerable<string> list) { 
    int len = 0; 
    foreach (string s in list) { 
     len = Math.Max(len, s.Length); 
    } 
    return len; 
} 

: 당신은 목록에서 읽는 방법을 원하는 경우에, 당신은 단지 읽기를 수있는 인터페이스를 사용합니다 예를 들어 문자열 배열과 같이 인터페이스를 구현하는 컬렉션을 사용할 수 있으므로 유연성이 향상됩니다.

일부 다른 언어는 메서드가 매개 변수를 변경하지 못하도록 매개 변수에 적용 할 수있는 const 키워드가 있습니다. .NET에는이 인터페이스와 변경할 수없는 문자열에 사용할 수있는 인터페이스가 있으므로 실제로는 const 매개 변수가 필요하지 않습니다.

관련 문제