문제

사람들이 코드 생성기와 T4 템플릿을 사용해서는 안된다고 말하는 것을 들었습니다. 그 뒤에있는 논리는 생성기로 코드를 생성하는 경우 제네릭과 템플릿을 통해 코드를 빌드하는 더 효율적인 방법이 있다는 것입니다.

위 의이 진술에 약간 동의하지만, 예를 들어 스스로를 인스턴스화 할 수있는 템플릿을 구축하는 효과적인 방법을 찾지 못했습니다. 다른 단어에서는 결코 할 수 없습니다.

return new T();

또한 데이터베이스 값을 기반으로 코드를 생성하려면 Microsoft.SqlServer.Management.SMO T4 템플릿과 함께 Resharper를 복사 / 붙여 넣거나 사용할 필요없이 대량의 코드를 생성하는 데 훌륭했습니다.

제가 제네릭에서 찾은 많은 문제는 충격에 대해 이해하지 못하는 많은 개발자가 있다는 것입니다. 솔루션에 대한 제네릭을 검사 할 때 C#은 내 마음에 논리적으로 보일 수있는 일을 할 수 없다고 말하기 때문에 복잡해지는 시간이 있습니다.

당신의 생각은 무엇입니까? 발전기를 구축하는 것을 선호합니까, 아니면 제네릭을 사용하는 것을 선호합니까? 또한 제네릭은 얼마나 멀리 갈 수 있습니까? 나는 제네릭에 대해 괜찮은 금액을 알고 있지만, 항상 T4 템플릿에 의지하게 만드는 함정과 함정이 있습니다.

많은 유연성이 필요한 시나리오를 처리하는 가장 적절한 방법은 무엇입니까? 아, 그리고이 질문에 대한 보너스로, C#과 제네릭의 좋은 자원은 무엇입니까?

도움이 되었습니까?

해결책

당신은 새로운 t ()를 할 수 있습니다. 당신이 이것을한다면

public class Meh<T>
  where T : new()
{
  public static T CreateOne()
  {
    return new T();
  }
}

코드 제너레이터에 관해서는. 나는 매일 아무 문제없이 사용합니다. 나는 지금 당장 하나를 사용하고 있습니다 :-)

제네릭은 하나의 문제를 해결하고 코드 제너레이터는 다른 문제를 해결합니다. 예를 들어, UML 편집기를 사용하여 비즈니스 모델을 작성한 다음 항상 사용하는 동안 지속성 코드로 클래스를 생성합니다. 이 도구 각 영구 클래스는 완전히 다르기 때문에 제네릭으로 달성 할 수 없습니다.

제네릭에 대한 좋은 소스는. 최고는 있어야합니다 Jon Skeet의 책 물론이야! :-)

다른 팁

T4의 창시자로서, 나는 당신이 상상할 수있는 대로이 질문을 상당히 몇 번 방어해야했습니다 :-)

저의 믿음은 최고의 코드 생성에서 재사용 가능한 라이브러리를 사용하여 동등한 가치를 생성하는 단계의 단계라는 것입니다.

다른 많은 사람들이 말했듯이 건조를 유지하는 핵심 개념은 수동으로 생성 된 코드를 변화시키지 않고 소스 메타 데이터가 변경되거나 코드 생성기에서 버그를 찾을 때 재생하는 능력을 보존하는 것입니다. 이 시점에서 생성 된 코드에는 객체 코드의 많은 특성이 있으며 복사/페이스트 유형 문제가 발생하지 않습니다.

일반적으로 사용 비용을 동일한 수준으로 낮추는 고품질 기본 라이브러리를 올바르게 엔지니어링하는 것보다 매개 변수화 된 코드 생성기 (특히 템플릿 기반 시스템)를 생성하려는 노력이 훨씬 적으므로 빠르게 얻는 방법입니다. 일관성으로 인한 값 및 반복 오류를 제거합니다.

그러나 나는 여전히 완성 된 시스템이 총 코드가 적음으로써 대부분 개선 될 것이라고 생각합니다. 다른 것이 없다면, 메모리 풋 프린트는 거의 항상 훨씬 작을 것입니다 (사람들은 제네릭을 이와 관련하여 무료로 생각하는 경향이 있지만, 가장 확실하지 않습니다).

코드 생성기를 사용하여 약간의 가치를 실현했다면, 이는 종종 생성 된 코드베이스에서 라이브러리를 수확하는 데 투자하기 위해 시간이나 돈이나 영업권을 구매합니다. 그런 다음 코드 생성기를 점진적으로 리엔지니어링하여 새 라이브러리를 타겟팅하고 훨씬 적은 코드를 생성 할 수 있습니다. 헹구고 반복하십시오.

나에게 만들어 졌고이 스레드에서 나온 흥미로운 반대 지점 중 하나는 풍부하고 복잡한 파라 메트릭 라이브러리가 학습 곡선 측면에서 가장 쉬운 일이 아니라는 것입니다. 더 간단한 기본 프레임 워크에 코드 생성을 고수하면 장황 코드를 생성 할 수 있지만 종종 매우 간단하고 읽기 쉽습니다.

물론 발전기에 많은 차이와 매우 풍부한 매개 변수화가있는 경우 템플릿의 복잡성을 위해 제품을 복잡하게 거래 할 수 있습니다. 이것은 빠른 길이이며 두통만큼 유지 보수를 만들 수 있습니다.이를 조심하십시오.

코드를 생성하는 것은 악하지 않고 냄새가 나지 않습니다! 열쇠는 적시에 올바른 코드를 생성하는 것입니다. 나는 T4가 훌륭하다고 생각합니다. 가끔 사용하지만 내가 할 때는 매우 도움이됩니다. 말하자면, 코드를 생성하는 것이 나쁘다는 것은 무조건 미쳤다!

코드 생성이 한 번 실행 한 다음 출력을 유지하는 것이 아니라 일반 빌드 프로세스의 일부인 경우 코드 생성기가 괜찮은 것 같습니다. 코드 생성기를 한 번만 사용하고 생성 된 데이터를 폐기하면 대규모 건조 위반 및 유지 보수 두통을 자동으로 생성하기 때문에이 경고를 추가합니다. 매번 코드를 생성한다는 것은 생성을 수행하기 위해 사용하는 것이 실제 소스 코드이며 생성 된 파일은 대부분 무시 해야하는 중간 컴파일 스테이지라는 것을 의미합니다.

Lex와 YACC는 기능을 효율적으로 지정하고 효율적인 코드를 생성 할 수있는 도구의 전형적인 예입니다. 직접 직무를 수행하려고하면 개발 시간이 길어지고 효율적이고 읽기 쉬운 코드가 덜 생성 될 수 있습니다. 또한 Lex 및 YACC와 같은 것을 코드에 직접 통합하고 컴파일 타임 대신 런타임에 작업을 수행 할 수 있지만 코드에 상당한 복잡성을 추가하고 속도를 늦출 수 있습니다. 실제로 실행 시간에 사양을 변경 해야하는 경우 가치가있을 수 있지만 대부분의 경우 LEX/YACC를 사용하여 컴파일 타임에 코드를 생성하는 것이 큰 승리입니다.

Code Generation 없이는 Visual Studio 2010에있는 것의 상당 부분이 불가능합니다. 엔티티 프레임 워크는 불가능합니다. 형태로 컨트롤을 끌고 삭제하는 간단한 행동은 불가능하지도 않을 것입니다. 코드 생성을 사용해서는 안된다고 말하는 것은 이상한 일입니다.

어쩌면 조금 가혹하지만 코드 생성 냄새가 나에게도.

코드 생성은 사용되면 "자신을 반복하지 말라"패션으로 표현 될 수있는 수많은 기본 공통 원칙이 있음을 의미합니다. 시간이 조금 더 걸릴 수 있지만 메커니즘을 포함하는 인프라를 기반으로 실제로 변하는 비트 만 포함하는 클래스로 끝날 때 만족 스럽습니다.

제네릭에 관해서는 ... 아니요, 나는 그것에 너무 많은 문제가 없습니다. 현재 작동하지 않는 유일한 것은

List<Animal> a = new List<Animal>();
List<object> o = a;

그러나 다음 버전의 C#에서도 가능할 것입니다.

더 많은 코드는 더 복잡하다는 것을 의미합니다. 더 복잡한 것은 버그가 숨길 수있는 더 많은 장소를 의미하며, 이는 더 긴 수정주기를 의미하며, 이는 프로젝트 전체에서 더 높은 비용을 의미합니다.

가능할 때마다 동등한 기능을 제공하기 위해 코드의 양을 최소화하는 것이 좋습니다. 코드 생성보다는 동적 (프로그래밍 방식) 접근법을 사용하는 것이 이상적입니다. 반사, 속성, 측면 및 제네릭은 건조한 전략을위한 많은 옵션을 제공하여 세대를 최후의 수단으로 남겨 둡니다.

코드 생성은 언어, 프레임 워크 등에서 발견되는 많은 문제에 대한 해결 방법입니다. 그들은 그 자체로 악하지 않습니다. 나는 언어 (c#)와 당신을 강요하는 프레임 워크를 발표하는 것이 매우 나쁘다는 말을 할 것입니다. 복사 및 붙여 넣기 (속성, 이벤트 트리거링, 매크로 부족) 또는 마법 숫자 (WPF 바인딩)를 사용하십시오.

그래서 나는 울지 만 나는 그들을 사용해야하기 때문에 그것들을 사용합니다.

코드 생성 및 제네릭에 T4를 사용했습니다. 둘 다 좋고 장단점이 있으며 다른 목적에 적합합니다.

제 경우에는 T4를 사용하여 데이터베이스 스키마를 기반으로 엔티티, DAL 및 BLL을 생성합니다. 그러나 DAL과 BLL은 제네릭과 반사를 기반으로 제작 한 미니 오스트를 참조합니다. 그래서 나는 당신이 통제력을 유지하고 작고 단순하게 유지하는 한 나란히 사용할 수 있다고 생각합니다.

T4는 정적 코드를 생성하고 제네릭은 동적입니다. 제네릭을 사용하는 경우 "하드 코딩 된"솔루션보다 성능이 떨어지는 반사를 사용합니다. 물론 반사 결과를 캐시 할 수 있습니다.

"return new t ();"에 대해서는 다음과 같은 동적 메소드를 사용합니다.

public class ObjectCreateMethod
    {
    delegate object MethodInvoker();
    MethodInvoker methodHandler = null;

    public ObjectCreateMethod(Type type)
    {
        CreateMethod(type.GetConstructor(Type.EmptyTypes));
    }

    public ObjectCreateMethod(ConstructorInfo target)
    {
        CreateMethod(target);
    }

    void CreateMethod(ConstructorInfo target)
    {
        DynamicMethod dynamic = new DynamicMethod(string.Empty,
                    typeof(object),
                    new Type[0],
                    target.DeclaringType);
        ILGenerator il = dynamic.GetILGenerator();
        il.DeclareLocal(target.DeclaringType);
        il.Emit(OpCodes.Newobj, target);
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ret);

        methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
    }

    public object CreateInstance()
    {
        return methodHandler();
    }
}

그런 다음 다음과 같이 부릅니다.

ObjectCreateMethod _MetodoDinamico = new ObjectCreateMethod(info.PropertyType);
object _nuevaEntidad = _MetodoDinamico.CreateInstance();

제네릭과 코드 생성은 두 가지 다른 것입니다. 경우에 따라 코드 생성 대신 제네릭을 사용할 수 있으며 귀하가 생각해야한다고 생각합니다. 다른 경우 코드 생성은 강력한 도구입니다.

일부 데이터 입력을 기반으로 코드를 생성 해야하는 모든 경우에 코드 생성이 진행됩니다. 가장 분명하지만 결코 유일한 예는 Visual Studio의 Forms 편집기입니다. 여기서 입력은 설계자 데이터이고 출력은 코드입니다. 이 경우 제네릭은 전혀 도움이되지 않지만 GUI 레이아웃에 따라 단순히 코드를 생성하는 것이 매우 좋습니다.

코드 생성기는 대상 Langauge의 결함 또는 기능 부족을 나타내는 코드 냄새로 간주 될 수 있습니다.

예를 들어, 여기서 "지속되는 객체는 일반화 될 수 없다"고 말하지만, "자동으로 데이터를 자동으로 유지하는 C#의 객체는 C#에서 일반화 될 수 없다"고 생각하는 것이 좋습니다. 다양한 방법을 사용하여 파이썬에서.

그러나 파이썬 접근법은 요구 사항에 따라 연산자 [] (Method_name AS String)를 사용하여 정적 언어로 모방 될 수 있습니다. 불행히도 해당 솔루션은 항상 적용되는 것은 아니며 undector를 반환하는 것은 불편할 수 있습니다.

내가 만드는 요점은 코드 생성기가보다 편리한 것을 제공함으로써 해결 된 언어의 결함을 나타내는 것입니다. 전문 당면한 특정 문제에 대한 구문.

생성 된 코드의 복사/페이스트 유형 (Orms Make와 같은)도 매우 유용 할 수 있습니다 ...

데이터베이스를 작성한 다음 ORM이 좋아하는 언어로 표현 된 해당 데이터베이스 정의 사본을 생성하도록 할 수 있습니다.

원래 정의 (데이터베이스)를 변경하고 Compile을 누르면 ORM (좋은 경우)이 정의 사본을 다시 생성 할 수 있습니다. 이제 데이터베이스에 대한 모든 참조는 컴파일러 유형 검사기에서 확인할 수 있으며 더 이상 존재하지 않는 테이블이나 열을 사용할 때 코드가 컴파일하지 못합니다.

이것에 대해 생각해보십시오 : 내 코드에서 메소드를 몇 번 호출하면 원래이 방법에 준 이름을 참조하지 않습니까? 나는 그 이름을 계속 반복하고 있습니다 ... 언어 디자이너들은이 문제를 인식하고 솔루션으로 "유형 안전성"을 생각해 냈습니다. 사본을 제거하지 않으면 (드라이가해야한다고 제안하는 것처럼) 대신 정확성을 확인하십시오.

ORM 생성 코드는 테이블 및 열 이름을 참조 할 때 동일한 솔루션을 제공합니다. 사본/참조를 제거하지 않고 대신 클래스와 속성을 참조 할 수있는 (유형-안전) 언어로 데이터베이스 정의를 가져 오십시오. 컴파일러 유형 확인과 함께 비슷한 방식으로 유사한 문제를 해결합니다. 구식 또는 틀린 테이블 (클래스) 또는 열 (속성)을 참조 할 때 런타임 오류 대신 컴파일 타임 오류를 보장합니다.

인용문 : 나는 예를 들어 스스로를 인스턴스화하는 것과 같은 템플릿을 만들 수있는 효과적인 방법을 찾지 못했습니다. 다른 단어에서는 결코 할 수 없습니다.

새로운 t ()를 반환합니다.

public abstract class MehBase<TSelf, TParam1, TParam2>
    where TSelf : MehBase<TSelf, TParam1, TParam2>, new()
{
    public static TSelf CreateOne()
    {
        return new TSelf();
    }
}

public class Meh<TParam1, TParam2> : MehBase<Meh<TParam1, TParam2>, TParam1, TParam2>
{
    public void Proof()
    {
        Meh<TParam1, TParam2> instanceOfSelf1 = Meh<TParam1, TParam2>.CreateOne();
        Meh<int, string> instanceOfSelf2 = Meh<int, string>.CreateOne();
    }
} 

제네릭, 템플릿 및 기타 바로 가기와 같은 코드 생성은 강력한 도구입니다. 그리고 가장 강력한 도구와 마찬가지로, 그것은 선과 악을 위해 사용자의 통근성을 증폭시킵니다. 그들은 분리 될 수 없습니다.

따라서 코드 생성기를 철저히 이해하면 생산할 모든 것을 예상하고 그 이유를 예상하고 유효한 이유로 그렇게하려고합니다. 그러나 어디로 향했는지 또는 거기에가는 방법을 확신하지 못하는 곳을 지나치게하기 위해 (또는 다른 기술 중 하나)를 사용하지 마십시오.

어떤 사람들은 현재 문제를 해결하고 일부 행동이 구현되면 황금색이라고 생각합니다. 다음 개발자를 위해 트레일에 얼마나 많은 Cruft와 Opaquenes가 떠나는지는 항상 분명하지는 않습니다.

왜 정말로, 정말 빠르게 복사/붙여 넣을 수있게되면 더 많은 것을 받아 들일 수 있습니까?

그것이 제가 볼 수있는 코드 생성에 대한 유일한 정당화입니다.

발전기가 필요한 모든 유연성을 제공하더라도 여전히 유연성을 사용하는 방법을 배워야합니다. 이는 또 다른 학습 및 테스트 계층입니다.

그리고 제로 시간 안에 실행 되더라도 여전히 코드가 부풀어 오릅니다.

나는 내 자신의 데이터 액세스 클래스를 굴 렸습니다. 연결, 트랜잭션, 저장 프로 시저 파크 등에 대한 모든 것을 알고 있으며 모든 ado.net을 한 번만 작성해야했습니다.

연결 객체가있는 것을 써서 (또는 심지어 봐야) 지금은 너무 오래 걸렸으므로 구문을 기억하기가 어려워졌습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top