Programing

매개 변수 이름 반영 : C # 람다 식 남용 또는 구문 광택?

lottogame 2020. 2. 19. 21:21
반응형

매개 변수 이름 반영 : C # 람다 식 남용 또는 구문 광택?


MvcContrib Grid 구성 요소를 보고 있으며 Grid 구문에 사용되는 구문 트릭에 매료되었지만 동시에 반박했습니다 .

.Attributes(style => "width:100%")

위의 구문은 생성 된 HTML의 스타일 속성을로 설정합니다 width:100%. 이제주의를 기울이면 '스타일'이 지정되지 않으며 표현식의 매개 변수 이름 에서 추론됩니다 ! 나는 이것을 파헤쳐 서 '매직'이 일어나는 곳을 찾았습니다.

Hash(params Func<object, TValue>[] hash)
{
    foreach (var func in hash)
    {
        Add(func.Method.GetParameters()[0].Name, func(null));
    }
}

실제로 코드는 형식, 컴파일 시간, 매개 변수 이름을 사용하여 속성 이름-값 쌍의 사전을 만듭니다. 결과 구문 구조는 실제로 매우 표현력이 높지만 동시에 매우 위험합니다. 람다 식을 일반적으로 사용하면 부작용없이 사용 이름 을 대체 할 수 있습니다 . 나는라는 책에서 예를 볼 collection.ForEach(book => Fire.Burn(book))나는 내 코드에서 쓸 수 있습니다 알고 collection.ForEach(log => Fire.Burn(log))그리고 그것은 같은 일을 의미합니다 . 그러나 MvcContrib Grid 구문이 갑자기 여기에서 변수에 대해 선택한 이름을 기반으로 적극적으로보고 결정하는 코드를 찾습니다!

C # 3.5 / 4.0 커뮤니티 및 람다 식 애호가들과의 공통 관행입니까? 아니면 내가 걱정해서는 안되는 악성 트릭 매버릭입니까?


상호 운용성이 좋지 않습니다. 예를 들어,이 C #-F # 예를 고려하십시오.

씨#:

public class Class1
{
    public static void Foo(Func<object, string> f)
    {
        Console.WriteLine(f.Method.GetParameters()[0].Name);
    }
}

에프#:

Class1.Foo(fun yadda -> "hello")

결과:

"arg"가 인쇄됩니다 ( "yadda"아님).

결과적으로 라이브러리 디자이너는 이러한 종류의 '부적절 함'을 피하거나 .Net 언어에서 좋은 상호 운용성을 원할 경우 최소한 '표준'과부하 (예 : 문자열 이름을 추가 매개 변수로 사용)를 제공해야합니다.


나는 이름 때문에 그다지 이상한 것이 아니라 람다가 불필요 하기 때문에 ; 익명 유형을 사용하고 더 유연 할 수 있습니다.

.Attributes(new { style = "width:100%", @class="foo", blip=123 });

이것은 많은 ASP.NET MVC에서 사용되는 패턴이며 (예를 들어) 다른 용도로 사용됩니다 ( 주의 사항 은 호출자 고유의 이름이 아닌 마법의 가치 인 경우 Ayende의 생각에 주의 하십시오 )


내 의견을 던지고 싶었습니다 (MvcContrib 그리드 구성 요소의 저자입니다).

이것은 분명히 언어 남용입니다. 의심 할 여지가 없습니다. 그러나, 나는 그것이 직감적이라고 생각하지 않을 것입니다-당신이 전화를 볼 때 Attributes(style => "width:100%", @class => "foo")
무슨 일이 일어나고 있는지 분명하다고 생각합니다 (익명 유형 접근법보다 나쁘지 않습니다). 지능적인 관점에서 나는 그것이 불투명하다는 데 동의합니다.

관심있는 사람들을 위해 MvcContrib에서의 사용에 대한 배경 정보는 ...

나는 이것을 개인 취향으로 그리드에 추가했다-나는 익명의 타입을 사전으로 사용하는 것을 좋아하지 않는다 ( "object"를 취하는 매개 변수가 Func []라는 매개 변수를 갖는 것만 큼 불투명하다); 오히려 장황한 (또한 Attribute ( "style", "display : none"). Attribute ( "class", "foo") 등 여러 호출을 함께 연결해야하는 장황한 인터페이스에 대한 팬이 아닙니다.

C #에 사전 리터럴에 대한 덜 장황한 구문이 있다면 그리드 구성 요소 에이 구문을 포함시키지 않아도됩니다.

또한 MvcContrib에서 이것을 사용하는 것은 완전히 선택적이라는 것을 지적하고 싶습니다. 이들은 대신 IDictionary를 사용하는 과부하를 감싸는 확장 방법입니다. 이와 같은 방법을 제공하는 경우 다른 언어와의 상호 운용을 위해보다 '일반적인'접근 방식도 지원해야합니다.

또한 누군가가 '반사 오버 헤드'를 언급 했으며이 접근법에는 실제로 오버 헤드가 많지 않다는 것을 지적하고 싶었습니다. 런타임 리플렉션이나 식 컴파일이 필요하지 않습니다 ( http://blog.bittercoder.com 참조) /PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx ).


내가 선호하는

Attributes.Add(string name, string value);

훨씬 더 명확하고 표준이며 람다를 사용하여 얻은 것은 없습니다.


Rails Land에 오신 것을 환영합니다 :)

무슨 일이 일어나고 있는지 아는 한 아무런 문제가 없습니다. (이런 종류의 문제가 문서화되어 있지 않은 경우).

Rails 프레임 워크 전체는 컨피규레이션에 대한 컨벤션에 기반을두고 있습니다. 특정 방식으로 이름을 지정하면 사용중인 컨벤션에 참여하게되며 많은 기능이 무료로 제공됩니다. 명명 규칙을 따르면 더 빨리가는 곳으로 갈 수 있습니다. 모든 것이 훌륭하게 작동합니다.

이와 같은 트릭을 본 또 다른 곳은 Moq의 메소드 호출 어설 션입니다. 람다를 전달하지만 람다는 절대 실행되지 않습니다. 단지 표현식을 사용하여 메소드 호출이 발생했는지 확인하고 그렇지 않은 경우 예외를 발생시킵니다.


이것은 하나 이상의 수준에서 끔찍 합니다. 그리고 아니, 이것은 루비와 같은 것이 아닙니다. C #과 .Net의 남용입니다.

튜플, 익명 형식, 유창한 인터페이스 등과 같이보다 직접적인 방법으로이를 수행하는 방법에 대한 제안이 많이있었습니다.

그렇게 나쁘게 만드는 것은 자신의 이익을 위해 공상하는 올바른 방법이라는 것입니다.

  • VB에서 이것을 호출하면 어떻게됩니까?

    .Attributes(Function(style) "width:100%")

  • 직관적으로 지능적인 인텔리전스를 사용하면 물건을 전달하는 방법을 알아내는 데 거의 도움이되지 않습니다.

  • 불필요하게 비효율적입니다.

  • 아무도 그것을 유지하는 방법에 대한 단서가 없습니다.

  • 속성에 들어가는 인수의 유형은 무엇입니까 Func<object,string>? 그 의도가 어떻게 드러납니까? "문서의 모든 값을 무시하십시오"라는 지적 문서는 무엇입니까?

나는 당신이 그런 반감을 느끼는 것을 완전히 정당화했다고 생각합니다.


나는 "syntax brilliance"캠프에 있는데, 그것들이 명확하게 문서화되어 있고,이 굉장히 멋져 보인다면, 문제가 거의 없습니다!


둘 다. 그것은 람다 식의 abusage의 AND 구문 광택.


나는 이런 종류의 사용법을 거의 보지 못했습니다. 나는 그것이 "부적절하다"고 생각합니다 :)

이것은 일반적인 사용 방법이 아니며 일반적인 규칙과 일치하지 않습니다. 이런 종류의 구문에는 물론 장단점이 있습니다.

단점

  • 코드가 직관적이지 않습니다 (일반적인 규칙이 다릅니다)
  • 깨지기 쉬운 경향이 있습니다 (매개 변수 이름을 바꾸면 기능이 작동하지 않습니다).
  • 테스트하기가 조금 더 어렵습니다 (API를 가짜로하려면 테스트에서 리플렉션을 사용해야합니다).
  • 표현식을 집중적으로 사용하는 경우 값 (반사 비용)뿐만 아니라 매개 변수를 분석해야하기 때문에 속도가 느려집니다.

찬성

  • 개발자가이 구문으로 조정 한 후에 더 읽기 쉽습니다.

결론 -공개 API 디자인에서 더 명확한 방법을 선택했을 것입니다.


아니요, 확실히 일반적인 관행은 아닙니다. 반 직관적이므로 코드를보고 그 기능을 파악할 수있는 방법이 없습니다. 어떻게 사용되는지 이해하기 위해 어떻게 사용되는지 알아야합니다.

델리게이트 배열을 사용하여 속성을 제공하는 대신 연결 방법이 더 명확하고 성능이 우수합니다.

.Attribute("style", "width:100%;").Attribute("class", "test")

이것은 타이핑하기에 조금 더 좋지만 명확하고 직관적입니다.


이것을 사용하여 문구를 만들 수 있습니까?

매직 람다 (n) : 매직 스트링을 대체 할 목적으로 만 사용되는 람다 함수.


다음과 같은 문제가 있습니다.

html.Attributes["style"] = "width:100%";

"회심"에 대한이 모든 논쟁은 오랜 시간 동안 C #을 과도하게 반응하는 사람들입니다 (그리고 저는 오랫동안 C # 프로그래머이자 여전히 언어의 열렬한 팬입니다). 이 구문에는 끔찍한 것이 없습니다. 구문을 표현하려는 것과 비슷하게 만들려는 시도 일뿐입니다. 무언가 구문에 "소음"이 적을수록 프로그래머가 쉽게 이해할 수 있습니다. 한 줄의 코드에서 노이즈를 줄이면 약간 도움이되지만 점점 더 많은 코드를 빌드하게되면 실질적인 이점으로 판명됩니다.

이것은 저자가 DSL이 제공하는 것과 동일한 이점을 얻으려고 시도하는 것입니다. 코드가 말하려는 것처럼 "만일"때 마법의 장소에 도달했습니다. 이것이 interop에 적합한 지 또는 "복잡성"비용의 일부를 정당화 할 수있는 익명의 방법보다 충분히 좋은지에 대해 토론 할 수 있습니다. 충분히 공평합니다. 따라서 프로젝트에서 이러한 종류의 구문을 사용할지 여부를 올바르게 선택해야합니다. 그러나 여전히 ... 이것은 프로그래머가 하루가 끝날 무렵에 우리가하려고하는 일을하려고하는 영리한 시도입니다. 그리고 우리 모두가하려고하는 것은 이것입니다. "우리가 원하는 것을 생각하는 방식에 가능한 한 가까운 언어로 컴퓨터에게 말하십시오."

내부적으로 소프트웨어를 유지 관리하기 쉽고 정확하게 만드는 열쇠라고 생각하는 것과 같은 방식으로 컴퓨터에 지시 사항을 표현하는 방법

편집 : 나는 "소프트웨어를 유지 관리하고 더 정확하게 유지하는 열쇠"라고 말했다. "키"로 변경했습니다.


이는 표현식 트리의 장점 중 하나입니다. 추가 정보는 코드 자체를 검사 할 수 있습니다. 이것이 .Where(e => e.Name == "Jamie")동등한 SQL Where 절로 변환 될 수있는 방법 입니다. 이것은 표현 트리를 영리하게 사용하지만, 이것보다 더 이상 가지 않기를 바랍니다. 더 복잡한 것은 교체하려는 코드보다 어려울 수 있으므로 자체 제한이 의심됩니다.


흥미로운 접근법입니다. 표현식의 오른쪽을 상수로만 제한하면 다음을 사용하여 구현할 수 있습니다.

Expression<Func<object, string>>

내가 생각하는 것은 대리인 대신 실제로 원하는 것입니다 (람다를 사용하여 양쪽 이름을 얻습니다) 아래 순진한 구현을 참조하십시오.

public static IDictionary<string, string> Hash(params Expression<Func<object, string>>[] hash) {
    Dictionary<string, string> values = new Dictionary<string,string>();
    foreach (var func in hash) {
        values[func.Parameters[0].Name] = ((ConstantExpression)func.Body).Value.ToString();
    }
    return values;
}

이것은 스레드에서 앞서 언급 한 상호 언어 간 문제를 해결할 수도 있습니다.


코드는 매우 영리하지만 잠재적으로 더 많은 문제가 발생합니다.

지적했듯이 이제 매개 변수 이름 (스타일)과 HTML 특성간에 불명확 한 종속성이 있습니다. 컴파일 시간 검사가 수행되지 않습니다. 매개 변수 이름을 잘못 입력하면 페이지에 런타임 오류 메시지가 표시되지 않지만 논리 버그를 찾기가 훨씬 어렵습니다 (오류는 없지만 잘못된 동작).

더 나은 솔루션은 컴파일 타임에 확인할 수있는 데이터 멤버를 갖는 것입니다. 그래서 이것 대신에 :

.Attributes(style => "width:100%");

Style 속성이있는 코드는 컴파일러에서 확인할 수 있습니다.

.Attributes.Style = "width:100%";

또는:

.Attributes.Style.Width.Percent = 100;

코드 작성자에게는 더 많은 작업이 필요하지만이 방법은 C #의 강력한 유형 검사 기능을 활용하여 버그가 코드에 먼저 들어 가지 않도록합니다.


실제로 루비 =)처럼 보입니다. 적어도 나에게 역동적 인 "조회"에 정적 리소스를 사용하는 것은 API 디자인 고려 사항에 맞지 않습니다.이 영리한 트릭이 해당 API에서 선택 사항이기를 바랍니다.

우리는 IDictionary에서 상속 받거나 값을 설정하기 위해 키를 추가 할 필요가 없을 때 PHP 배열처럼 동작하는 인덱서를 제공 할 수 있습니다. C #뿐만 아니라 .net 시맨틱의 올바른 사용이며 여전히 문서가 필요합니다.

도움이 되었기를 바랍니다


IMHO, 그것은 그것을하는 멋진 방법입니다. 우리는 클래스 컨트롤러의 이름을 MVC의 컨트롤러로 지정한다는 사실을 좋아합니다. 따라서 이름이 중요한 경우가 있습니다.

또한 그 의도는 매우 분명합니다. 그것은 그 이해하는 것이 매우 쉽게 .Attribute( book => "something")발생합니다 book="something".Attribute( log => "something")발생합니다log="something"

컨벤션처럼 취급한다면 문제가되지 않을 것 같습니다. 코드를 적게 작성하고 의도를 분명하게 만드는 것은 좋은 일이라고 생각합니다.


내 생각에 그것은 람다의 남용입니다.

구문의 광채에 관해서는 style=>"width:100%"혼란스러워합니다. 특히 =>대신에=


방법 (func) 이름을 잘 선택하면 유지 관리 문제를 피할 수있는 훌륭한 방법입니다 (예 : 새 func를 추가하지만 function-parameter mapping 목록에 추가하는 것을 잊었습니다). 물론 문서를 많이 문서화해야하며 해당 클래스의 함수에 대한 문서에서 매개 변수에 대한 문서를 자동 생성하는 것이 좋습니다.


나는 이것이 "매직 스트링"보다 낫다고 생각합니다. 나는 이것에 대한 익명 유형의 팬이 아닙니다. 더 좋고 강력한 형식의 접근 방식이 필요합니다.

참고 : https://stackoverflow.com/questions/1718037/reflecting-parameter-name-abuse-of-c-sharp-lambda-expressions-or-syntax-brillia



반응형