제네릭 악용이란 무엇입니까?


35

일부 코드를 검토하는 동안 제네릭을 사용하도록 코드를 변경할 수있는 기회를 발견했습니다. (난독 화 된) 코드는 다음과 같습니다.

public void DoAllTheThings(Type typeOfTarget, object[] possibleTargets)
{
    var someProperty = typeOfTarget.GetProperty(possibleTargets[0]);
    ...
}

이 코드는 다음과 같이 제네릭으로 대체 될 수 있습니다.

public void DoAllTheThings<T>(object[] possibleTargets[0])
{
    var someProperty = type(T).getProperty(possibleTargets[0]);
    ...
}

이 접근법의 장점과 단점을 연구하면서 나는 일반적인 학대 라는 용어를 발견했다 . 보다:

내 질문은 두 부분으로 나옵니다.

  1. 이와 같은 제네릭으로 이전하면 어떤 이점이 있습니까? (성능? 가독성?)
  2. 제네릭 악용이란 무엇입니까? 그리고 유형 매개 변수가 남용 될 때마다 제네릭을 사용하고 있습니까?

2
혼란 스러워요. 속성의 이름을 미리 알고 있지만 객체의 유형은 알지 못하므로 리플렉션을 사용하여 값을 얻습니까?
MetaFight

3
@MetaFight 나는 복잡한 예제를 알고 있습니다. 실제 코드는 길고 여기에 넣기가 어려울 것입니다. 어쨌든 내 질문의 목적은 Type 매개 변수를 제네릭으로 바꾸는 것이 좋은지 나쁜지 아닌지 결정하는 것입니다.
SyntaxRules 2012

12
나는 항상 그것이 제네릭이 존재하는 전형적인 이유라고 생각했습니다 (맛있는 말장난이 아닙니다). 타이프 시스템을 활용하여 타이프를 직접 할 수있는 이유는 무엇입니까?
MetaFight

2
당신의 예는 더 위대하지만, 많은 IoD 라이브러리가하는 일이라고 생각합니다.
Ewan

14
답은 아니지만 두 번째 예는 첫 번째 예보다 융통성이 적습니다. 일반 함수를 작성하면 런타임 유형을 전달할 수있는 기능이 제거됩니다. 제네릭은 컴파일 타임에 유형을 알아야합니다.
KChaloux

답변:


87

제네릭이 적절하게 적용되면 코드를 재정렬하는 대신 코드를 제거 합니다. 기본적으로 제네릭이 제거하는 데 가장 적합한 코드는 유형 변환, 리플렉션 및 동적 입력입니다. 따라서 제네릭 남용은 일반적이지 않은 구현에 비해 유형 변환, 리플렉션 또는 동적 타이핑을 크게 줄이지 않고 일반 코드를 생성하는 것으로 느슨하게 정의 될 수 있습니다.

귀하의 예와 관련하여, 나는 제네릭을 적절하게 사용하여 object[]T[]또는 유사 하게 변경 하고 피 Type하거나 type완전히 피할 것으로 기대 합니다. 다른 곳에서는 상당한 리팩토링이 필요할 수 있지만,이 경우 제네릭을 사용하는 것이 적절하다면 작업이 끝날 때 전체적으로 더 단순 해집니다.


3
좋은 지적입니다. 나는 이것을 생각하기 어려운 코드를 읽기가 어렵다는 것을 인정할 것이다. 내가 바꿀 수 있는지 볼 수 있습니다 object[]T[].
SyntaxRules

3
나는 제거 대 재 배열 특성을 좋아한다.
copper.hat

13
중복을 줄이기 위해 제네릭을 사용하는 주요 기능 중 하나를 놓쳤습니다. (당신이 언급 한 다른 죄를 소개함으로써 중복을 줄일 수 있습니다). 타입 캐스트, 리플렉션 또는 동적 타이핑 IMO를 제거하지 않고 복제를 줄이면 괜찮습니다.
마이클 앤더슨

4
훌륭한 답변입니다. 이 특별한 경우에는 OP가 제네릭 대신 인터페이스 로 전환해야 할 수도 있습니다 . 반사가 객체의 특정 속성에 액세스하는 데 사용되는 것처럼 보입니다. 컴파일러가 그러한 속성이 실제로 존재하는지 확인할 수 있도록 인터페이스가 훨씬 더 적합합니다.
jpmc26

4
@MichaelAnderson "그냥 코드를 다시 정렬하는 대신 코드 제거"에는 중복 감소가 포함됩니다
Caleth

5

나는 말도 안되는 규칙을 사용합니다. 제네릭은 다른 모든 프로그래밍 구성과 마찬가지로 문제를 해결하기 위해 존재합니다 . 제네릭을 해결하는 데 문제가없는 경우 제네릭을 사용하는 것은 남용입니다.

제네릭의 특정 경우에, 그것들은 대부분 구체적인 타입에서 추상화되어 다른 타입에 대한 코드 구현이 하나의 일반적인 템플릿 (또는 언어가 호출하는 모든 것)으로 함께 접힐 수있게합니다. 이제 type을 사용하는 코드가 있다고 가정합니다 Foo. 해당 유형을 generic로 대체 할 수 T있지만 작업 할 때 해당 코드 만 필요한 Foo경우 함께 접을 수있는 다른 코드는 없습니다. 따라서, 해결 될 문제가 없으므로, 제네릭을 추가하는 간접 지시는 가독성을 감소시키는 역할을한다.

결과적으로 제네릭을 사용하지 않고 코드를 작성하는 것이 좋습니다 (두 번째 인스턴스화가 필요하기 때문에). 그러면 제네릭을 사용하도록 코드를 리팩터링해야 할 때입니다. 그 시점 이전의 사용은 내 눈에 남용입니다.


이것은 약간 너무 비현실적인 것처럼 들리므로 다음과 같이 상기시켜 드리겠습니다.
프로그래밍에는 예외가없는 규칙이 없습니다. 이 규칙이 포함되었습니다.


재미있는 생각. 그러나 기준을 약간 바꾸면 도움이 될 수 있습니다. OP에 int를 문자열에 매핑하거나 그 반대로 매핑하는 새로운 "구성 요소"가 필요하다고 가정합니다. 그것이 일반적인 요구를 해결하고 나중에 일반화되면 쉽게 재사용 할 수 있음이 매우 분명합니다. 이 경우는 제네릭 악용에 대한 정의에 해당합니다. 그러나 일단 매우 일반적인 근본적인 필요성이 파악되면, 이것이 남용되지 않고 디자인에 무의미한 추가 노력을 투자하는 것이 가치가 없을까요?
Christophe

@Christophe 정말 까다로운 질문입니다. 예, 실제로 내 규칙을 무시하는 것이 더 좋은 상황이 있습니다 (프로그래밍에 예외가없는 규칙은 없습니다!). 그러나 특정 문자열 변환 사례는 실제로 다소 관련이 있습니다. 1. 부호있는 정수 유형과 부호없는 정수 유형을 별도로 처리해야합니다. 2. 부동 변환은 정수 변환과 별도로 처리해야합니다. 3. 더 작은 유형의 경우 사용 가능한 가장 큰 정수 유형의 구현을 재사용 할 수 있습니다. 캐스팅을 수행하기 위해 제네릭 래퍼를 사전에 작성하고 싶을 수도 있지만 코어에는 제네릭이 없습니다.
cmaster

1
나는 YAGNI처럼 일반적인 (재사용보다는 사전 사용)을 사전에 작성하는 것에 반대합니다. 필요할 때 리팩터링하십시오.
Neil_UK

이 질문을 썼을 때 나는 "가능한 미래에 재사용 할 수 있도록 가능한 한 일반적인 것으로 쓰십시오"라는 자세를 취했습니다. 나는 그것이 약간 극단적이라는 것을 알고 있었다. 여기에서 귀하의 관점을 보는 것이 상쾌합니다. 감사!
SyntaxRules

0

코드가 이상하게 보입니다. 그러나 우리가 호출하면 유형을 제네릭으로 지정하는 것이 좋습니다.

https://stackoverflow.com/questions/10955579/passing-just-a-type-as-a-parameter-in-c-sharp

개인적으로 나는 호출 코드를 예쁘게 보이게 만드는 이러한 왜곡을 좋아하지 않습니다. 예를 들어 전체 '유창한'것과 확장 방법.

그러나 다음과 같은 인기가 있음을 인정해야합니다. 마이크로 소프트조차도 예를 들어 통일적으로 사용

container.RegisterType<IInterface,Concrete>()

0

나에게 그것은 당신이 올바른 길을 가고있는 것처럼 보이지만 일을 끝내지 못했습니다.

다음 단계 에서 object[]매개 변수 변경을 고려 했습니까 Func<T,object>[]?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.