[C#] C # 4.0의 ‘동적’유형은 무엇입니까?

C # 4.0에는 ‘dynamic’이라는 새로운 유형이 도입되었습니다. 그것은 모두 좋은 것처럼 들리지만 프로그래머는 그것을 위해 무엇을 사용할 것입니까?

하루를 구할 수있는 상황이 있습니까?



답변

dynamic 키워드는 C # 4.0에 새로 도입되었으며 컴파일러에 변수 유형이 변경 될 수 있거나 런타임까지 알려지지 않았 음을 컴파일러에 알리는 데 사용됩니다. 그것을 던질 필요없이 Object와 상호 작용할 수 있다고 생각하십시오.

dynamic cust = GetCustomer();
cust.FirstName = "foo"; // works as expected
cust.Process(); // works as expected
cust.MissingMethod(); // No method found!

cust를 고객 유형으로 캐스트하거나 선언 할 필요는 없습니다. 우리는 동적으로 선언했기 때문에 런타임은 우리를 대신하여 FirstName 속성을 검색하고 설정합니다. 물론 동적 변수를 사용하면 컴파일러 유형 검사를 포기하게됩니다. 이것은 cust.MissingMethod () 호출이 컴파일되고 런타임까지 실패하지 않음을 의미합니다. MissingMethod가 Customer 클래스에 정의되어 있지 않으므로이 작업의 결과는 RuntimeBinderException입니다.

위의 예제는 메소드와 속성을 호출 할 때 동적 작동 방식을 보여줍니다. 또 다른 강력하고 잠재적으로 위험한 기능은 다른 유형의 데이터에 변수를 재사용 할 수 있다는 것입니다. 필자는 Python, Ruby 및 Perl 프로그래머가 이것을 활용하는 백만 가지 방법을 생각할 수 있다고 확신하지만 C #을 오랫동안 사용하여 나에게 “잘못된”느낌을줍니다.

dynamic foo = 123;
foo = "bar";

OK, 따라서 위와 같은 코드를 자주 작성하지 않을 것입니다. 그러나 변수 재사용이 도움이되거나 더러운 레거시 코드를 정리할 수있는 경우가 있습니다. 내가 자주 겪는 한 가지 간단한 사례는 십진법과 이중 법 사이에서 끊임없이 캐스트해야한다는 것입니다.

decimal foo = GetDecimalValue();
foo = foo / 2.5; // Does not compile
foo = Math.Sqrt(foo); // Does not compile
string bar = foo.ToString("c");

2.5는 double로 입력되기 때문에 두 번째 줄은 컴파일되지 않으며 Math.Sqrt는 double을 기대하기 때문에 3 번째 줄은 컴파일되지 않습니다. 분명히, 당신이해야 할 일은 캐스트 및 / 또는 변수 유형을 변경하는 것이지만 동적이 사용하기에 적합한 상황이있을 수 있습니다.

dynamic foo = GetDecimalValue(); // still returns a decimal
foo = foo / 2.5; // The runtime takes care of this for us
foo = Math.Sqrt(foo); // Again, the DLR works its magic
string bar = foo.ToString("c");

더 많은 기능을 읽으십시오 : http://www.codeproject.com/KB/cs/CSharp4Features.aspx


답변

dynamic키워드는 C # 4.0의 다른 많은 새로운 기능과 함께 추가되어 다른 API에있는 다른 런타임에 있거나 다른 코드에서 쉽게 대화 할 수 있도록하기 위해 추가되었습니다.

예를 들어 보자.

개체와 같은 COM 개체가 Word.Application있고 문서를 열려고하는 경우 15 개 이상의 매개 변수가 제공되며 그 방법은 대부분 선택 사항입니다.

이 메소드를 호출하려면 다음과 같은 것이 필요합니다 (간단히 말하면 실제 코드는 아닙니다).

object missing = System.Reflection.Missing.Value;
object fileName = "C:\\test.docx";
object readOnly = true;
wordApplication.Documents.Open(ref fileName, ref missing, ref readOnly,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing);

그 모든 주장에 주목하십니까? 버전 4.0 이전에 C #부터 선택적 인수 개념이 없으므로이를 전달해야합니다. C # 4.0에서는 다음을 도입하여 COM API를보다 쉽게 ​​사용할 수 있습니다.

  1. 선택적 인수
  2. refCOM API에 대한 선택적 작성
  3. 명명 된 인수

위의 호출에 대한 새로운 구문은 다음과 같습니다.

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

보기가 훨씬 쉬워지고 읽기 쉬워 지는지 확인하십시오.

그것을 분해하자 :

                                    named argument, can skip the rest
                                                   |
                                                   v
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
                                 ^                         ^
                                 |                         |
                               notice no ref keyword, can pass
                               actual parameter values instead

마술은 C # 컴파일러가 이제 필요한 코드를 삽입하고 런타임에서 새 클래스로 작업하여 이전과 거의 동일한 작업을 수행하지만 구문이 숨겨져 있다는 것입니다. 무엇을 온, 그리고 너무 많은 방법 . Anders Hejlsberg는 당신이 다른 “개념”을 불러야한다고 말하는 것을 좋아합니다. 그것은 당신이 일반적으로 손을 흔들고 올바른 순서로 일부 마법의 단어를 말해야하는 모든 것의 마법에 대한 일종의 말입니다. 특정 유형의 주문이 진행됩니다. COM 객체와 대화하는 오래된 API 방식은 그다지 많았습니다. 컴파일러가 코드를 컴파일하도록 동축하려면 많은 후프를 뛰어 넘어야했습니다.

인터페이스 나 클래스가없는 COM 개체와 대화하려고하면 버전 4.0 이전의 C #에서는 상황이 훨씬 더 많이 분해됩니다 IDispatch. 참조 만 있으면 됩니다.

그것이 무엇인지 모르는 경우 IDispatch기본적으로 COM 개체에 대한 반영입니다. IDispatch인터페이스를 사용하면 객체에 “저장으로 알려진 메소드의 ID 번호가 무엇입니까”를 요청하고 인수 값을 포함하는 특정 유형의 배열을 빌드 한 Invoke다음 IDispatch인터페이스에서 메소드를 호출하여 메소드를 호출하여 모든 메소드를 전달할 수 있습니다. 함께 관리 한 정보.

위의 Save 메소드는 다음과 같이 보일 수 있습니다 (확실히 올바른 코드는 아닙니다) :

string[] methodNames = new[] { "Open" };
Guid IID = ...
int methodId = wordApplication.GetIDsOfNames(IID, methodNames, methodNames.Length, lcid, dispid);
SafeArray args = new SafeArray(new[] { fileName, missing, missing, .... });
wordApplication.Invoke(methodId, ... args, ...);

문서를 열기 만하면됩니다.

VB는 선택적인 인수와 오랜 시간 전에 대부분의 것을 지원 하므로이 C # 코드는 다음과 같습니다.

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

기본적으로 C #은 표현력 측면에서 VB를 따라 잡지 만 COM뿐만 아니라 확장 가능하게하여 올바른 방식으로 수행합니다. 물론 이것은 VB.NET 또는 .NET 런타임 위에 구축 된 다른 언어에서도 사용할 수 있습니다.

IDispatch인터페이스에 대한 자세한 내용은 Wikipedia : IDispatch 에서 확인할 수 있습니다 . 정말 맛있어요.

그러나 파이썬 객체와 대화하고 싶다면 어떻게해야합니까? COM 객체에 사용되는 API와는 다른 API가 있으며 Python 객체도 동적이기 때문에 호출하기에 적합한 방법, 매개 변수 등을 찾으려면 마법을 반영해야합니다. 리플렉션, 파이썬을 위해 작성된 것, 위의 IDispatch 코드와 거의 비슷합니다.

그리고 루비에게? 여전히 다른 API입니다.

자바 스크립트? 같은 거래, 다른 API도 마찬가지입니다.

동적 키워드는 다음 두 가지로 구성됩니다.

  1. C #의 새로운 키워드 dynamic
  2. 다양한 유형의 객체를 처리하는 방법을 알고 dynamic키워드에 필요한 특정 API를 구현 하고 호출을 올바른 방식으로 매핑 하는 일련의 런타임 클래스입니다 . API도 문서화되어 있으므로 런타임에 포함되지 않은 오브젝트가있는 경우이를 추가 할 수 있습니다.

그러나 dynamic키워드는 기존 .NET 전용 코드를 대체하기위한 것이 아닙니다. 물론, 그렇게 할 수 는 있지만 그 이유 때문에 추가되지 않았으며 Anders Hejlsberg가있는 C # 프로그래밍 언어의 저자는 여전히 C #을 강력한 유형의 언어로 간주하고 희생하지 않을 것입니다. 그 원리.

이것은 다음과 같은 코드를 작성할 수 있음을 의미합니다.

dynamic x = 10;
dynamic y = 3.14;
dynamic z = "test";
dynamic k = true;
dynamic l = x + y * z - k;

그리고 컴파일하도록하자면, 그것은 일종의 매직-렛-피겨-아웃-무엇을-중요한-런-타임 시스템 유형의 의미가 아닙니다.

전체적인 목적은 다른 유형의 물체와 쉽게 대화 할 수 있도록하는 것이 었습니다.

인터넷에는 키워드, 지지자, 반대자, 토론, 맹세, 칭찬 등에 관한 많은 자료가 있습니다.

다음 링크로 시작한 다음 Google에서 더 자세히 알아보십시오.


답변

아무도 다중 디스패치를 언급하지 않은 것에 놀랐습니다 . 이 문제를 해결하는 일반적인 방법은 방문자 패턴을 통하는 것이며 항상 가능한 것은 아니므로 누적 된 is수표로 끝납니다 .

여기에 내 자신의 응용 프로그램의 실제 예가 있습니다. 대신에 :

public static MapDtoBase CreateDto(ChartItem item)
{
    if (item is ElevationPoint) return CreateDtoImpl((ElevationPoint)item);
    if (item is MapPoint) return CreateDtoImpl((MapPoint)item);
    if (item is MapPolyline) return CreateDtoImpl((MapPolyline)item);
    //other subtypes follow
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

당신은 :

public static MapDtoBase CreateDto(ChartItem item)
{
    return CreateDtoImpl(item as dynamic);
}

private static MapDtoBase CreateDtoImpl(ChartItem item)
{
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

private static MapDtoBase CreateDtoImpl(MapPoint item)
{
    return new MapPointDto(item);
}

private static MapDtoBase CreateDtoImpl(ElevationPoint item)
{
    return new ElevationDto(item);
}

하는 것으로는 첫 번째 경우에서 ElevationPoint의 서브 클래스 MapPoint와이 배치되어 있지 않은 경우 전에 MapPoint 이 도달되지 않습니다. 가장 가까운 매칭 방법이 호출되므로 동적 인 경우에는 해당되지 않습니다.

코드에서 짐작할 수 있듯이 ChartItem 개체에서 직렬화 가능한 버전으로 변환하는 동안 해당 기능이 유용했습니다. 방문자와 함께 코드를 오염시키고 싶지 않으며 ChartItem쓸모없는 직렬화 특정 속성으로 객체 를 오염시키고 싶지 않았습니다 .


답변

정적 유형 언어 (CLR)가 DLR (동적 언어 런타임)에서 실행되는 동적 언어 (python, ruby ​​…)와 상호 운용하기가 더 쉬워집니다 ( MSDN 참조) .

예를 들어 다음 코드를 사용하여 C #에서 XML의 카운터를 증가시킬 수 있습니다.

Scriptobj.SetProperty("Count", ((int)GetProperty("Count")) + 1);

DLR을 사용하면 동일한 작업에 다음 코드를 대신 사용할 수 있습니다.

scriptobj.Count += 1;

MSDN에는 다음과 같은 장점이 있습니다.

  • 동적 언어를 .NET Framework로 간단하게 포팅
  • 정적으로 유형이 지정된 언어에서 동적 기능 사용
  • DLR 및 .NET Framework의 향후 이점 제공
  • 라이브러리 및 객체 공유 가능
  • 빠른 동적 디스패치 및 호출 제공

자세한 내용은 MSDN 을 참조하십시오.


답변

사용 예 :

commun 속성 ‘CreationDate’가있는 많은 클래스를 사용합니다.

public class Contact
{
    // some properties

    public DateTime CreationDate { get; set; }
}

public class Company
{
    // some properties

    public DateTime CreationDate { get; set; }

}

public class Opportunity
{
    // some properties

    public DateTime CreationDate { get; set; }

}

‘CreationDate’속성의 값을 검색하는 commun 메소드를 작성하는 경우 리플렉션을 사용해야합니다.

    static DateTime RetrieveValueOfCreationDate(Object item)
    {
        return (DateTime)item.GetType().GetProperty("CreationDate").GetValue(item);
    }

‘동적’개념을 사용하면 코드가 훨씬 더 우아해집니다.

    static DateTime RetrieveValueOfCreationDate(dynamic item)
    {
        return item.CreationDate;
    }


답변

COM interop. 특히 나는 모른다. 그것을 위해 특별히 설계되었습니다.


답변

주로 RAD 및 Python 피해자가 코드 품질, IntelliSense 및 컴파일 타임 버그 감지 를 파괴하는 데 사용됩니다 .