C # 4.0의 '동적'유형은 무엇입니까?


236

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

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



COM 또는 동적 유형 언어로 작업 할 때 유용합니다. 예를 들어 언어 스크립팅에 루아 또는 파이썬을 사용하는 경우 일반 코드 인 것처럼 스크립팅 코드를 호출하는 것이 매우 편리합니다.
코드 InChaos


이 기사가 귀하의 질문에 대한 완전한 답변이 되었기
개발자

답변:


196

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


96
개인적 dynamic으로 표준 C # 기능과 정적 타이핑으로 또는 대부분 형식 유추 ( var) 로 해결할 수있는 문제를 해결하기 위해 in #을 사용하는 생각이 마음에 들지 않습니다 . DLR과의 상호 운용성 문제에 대해서만dynamic 사용해야 합니다 . c #과 같이 정적 유형의 언어로 코드를 작성하는 경우 코드를 작성하고 동적 언어를 에뮬레이션하지 마십시오. 그건 못 생겼어
Philip Daubmeier

40
dynamic코드에서 변수를 필요로하지 않는 곳에서 변수를 많이 사용하는 경우 (제곱근을 사용하는 예 에서처럼) 컴파일 시간 오류 검사를 깔끔하게 포기합니다. 대신 가능한 런타임 오류가 발생합니다.
Philip Daubmeier

33
대부분 괜찮지 만 몇 가지 사소한 오류가 있습니다. 첫째, dynamic은 변수 유형이 변경 될 수 있음을 의미하는 것은 올바르지 않습니다 . 문제가되는 변수는 "동적"유형입니다 (C # 언어의 관점에서, CLR의 관점에서 변수는 개체 유형 임). 변수의 유형은 절대 변하지 않습니다 . 변수 의 런타임 유형은 변수 유형과 호환되는 모든 유형이 될 수 있습니다. (또는 참조 유형의 경우 null 일 수 있습니다.)
Eric Lippert

15
두 번째 요점 : C #에는 이미 "무엇이든 넣을 수있는 변수 만들기"기능이 있습니다. 항상 object 유형의 변수를 만들 수 있습니다. dynamic에 대한 흥미로운 점은 첫 번째 단락에서 지적한 것입니다. dynamic은 의미 체계 분석이 런타임까지 지연되고 의미 체계 분석이 런타임 유형의 표현식에서 수행된다는 점을 제외하고는 객체와 거의 동일합니다. (대부분 예외가 있습니다.)
Eric Lippert

18
나는 일반적으로 키워드의 사용을 암시 적으로 옹호하고 있기 때문에 이것에 대한 하향 요점을 보냈습니다. Lasses의 답변에 완벽하게 설명 된 특정 목표를 가지고 있으며이 답변은 기술적으로 정확하지만 개발자를 타락시킬 수 있습니다.
8 비트 전문가

211

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에서 더 자세히 알아보십시오.


12
직렬화 해제 된 JSON 객체의 구조가 C #에 지정되어 있지 않은 웹 JSON API의 경우 COM 외에도 유용합니다. 예를 들어 System.Web.Helpers.Json 의 Decode 메서드 는 동적 개체를 반환합니다 .
dumbledad

"그들은 여전히 ​​C #을 강력한 형식의 언어로 간주한다"는 점을 제외하고 Eric Lippert는 "강력한 형식"의 팬아닙니다 .
앤드류 키튼

나는 그에게 동의하지 않지만 그것은 사실의 문제가 아니라 의견의 문제입니다. 나에게 "강하게 입력 된"이란 컴파일러가 컴파일 타임에 어떤 유형이 사용되는지 알고 있으므로 해당 유형에 대해 설정된 규칙을 적용한다는 것을 의미합니다. 규칙 검사 및 런타임 바인딩을 연기하는 동적 유형을 선택할 수 있다는 사실은 언어의 유형이 약하다는 것을 의미하지는 않습니다. 나는 보통 약한 타입과 약한 타입을 대조하지 않지만, 보통 파이썬과 같은 언어와 같이 동적으로 타이핑하는 것과 비교합니다.
Lasse V. Karlsen

이 답변의 요점은 무엇입니까? 그중 절반은 선택적 매개 변수와 IDispatch 인터페이스에 관한 것입니다.
Xam

이것이 dynamic리플렉션과 같은 메소드 호출이 수행 될 수있는 방법에 대한 다른 생태계를 지원하고이를 달성하기위한 문서화 된 방법으로 데이터 구조에 대한 일종의 블랙 박스 접근 방식을 제공하기 위해 추가 된 이유 입니다.
Lasse V. Karlsen '12

29

아무도 다중 디스패치를 언급하지 않은 것에 놀랐습니다 . 이 문제를 해결하는 일반적인 방법은 방문자 패턴을 통하는 것이며 항상 가능한 것은 아니므로 누적 된 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쓸모없는 직렬화 특정 속성으로 객체 를 오염시키고 싶지 않았습니다 .


이 사용 사례에 대해 몰랐습니다. 그래도 조금 해키. 정적 분석기를 버립니다.
Kugel

2
@Kugel 그건 사실이지만 나는 그것을 이라고 부르지 않을 것 입니다. 정적 분석은 좋지만, 개방형 원칙 위반 (방문자 패턴) 또는 is다른 하나의 위에 쌓인 더미 로 인한 순환 복잡성 증가와 같은 대안으로 우아한 솔루션을 막을 수는 없습니다 .
Stelios Adamantidis

4
C # 7과 패턴 일치 옵션이 있습니까?
Kugel

2
연산자는 그 방법보다 훨씬 저렴하며 (더블 캐스트는 피함) 정적 분석을 다시받습니다. ;-) 및 성능.
Kugel

@idbrii 내 답변을 변경하지 마십시오. 의견을 적어주십시오.이 커뮤니티에서 여전히 활동하고 있으므로 필요한 경우 명확하게 설명하겠습니다. 또한 사용하지 마십시오 magic; 마술 같은 것은 없습니다.
Stelios Adamantidis

11

정적 유형 언어 (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 을 참조하십시오.


1
그리고 동적에 필요한 VM의 변화는 실제로 동적 언어를 더 쉽게 만듭니다.
다이 캄

2
@Dykam : VM에는 변경 사항이 없습니다. DLR은 .NET 2.0으로 완벽하게 작동합니다.
Jörg W Mittag

@ Jörg, 네, 변화가 있습니다. DLR은 이제 VM이 동적 확인을 지원하도록 빌드 되었기 때문에 부분적으로 다시 작성되었습니다.
Dykam

나는 너무 낙관적이었다, 연구는 변화가 그렇게 크지 않다는 것을 보여 주었다.
Dykam

4

사용 예 :

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;
    }

7
오리 타자. 그러나 유형이 인터페이스 인 경우 인터페이스를 사용해야합니다.
Kugel

3

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


2

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


냉소적 인 답변이지만 쉽게 사실입니다. 코드가 제대로 작동하면 코드가 제대로 작동한다는 결과로 구조체를 선언하지 않으려 고하지만 치즈를 옮기 자마자 예측할 수없는 방식으로 스택을 날려 버렸습니다.
AnthonyVO

예, 다른 언어 기능이 많은 클래식 코너 커팅을 볼 수 있습니다. 여기에서도 볼 수 있다는 것은 놀라운 일이 아닙니다.
Hawkeye4040

1

런타임에 평가되므로 JavaScript에서와 같이 원하는 유형으로 유형을 전환 할 수 있습니다. 이것은 합법적입니다.

dynamic i = 12;
i = "text";

따라서 필요에 따라 유형을 변경할 수 있습니다. 최후의 수단으로 사용하십시오. 그것은 유익하지만 IL 생성이라는 측면에서 많은 일들이 진행되고 있으며 이는 성능 가격으로 올 수 있다고 들었습니다.


7
나는 그것이 "합법적"이라고 말하는 것을 주저 할 것입니다. 컴파일러는 이제 컴파일러가이를 컴파일하고 런타임이이를 실행한다는 의미에서 "레코드 코드"로 컴파일됩니다. 그러나 나는 내가 유지하는 코드 중 특정 코드 조각 (또는 코드와 비슷한 것)을보고 싶지 않거나 거의 화를내는 범죄 일 것입니다.
Lasse V. Karlsen

6
물론, "dynamic"대신 "object"를 사용하여 "legit"이되었을 것입니다. 역동성에 대해 흥미로운 것을 보여주지 않았습니다.
Eric Lippert

객체의 경우 실제로 메소드를 호출하려면 적절한 유형으로 캐스팅해야합니다. 서명을 잃어 버립니다. 컴파일 오류없이 코드가 모든 메소드를 호출하도록 할 수 있으며 런타임시 오류가 발생합니다. 서둘러 입력 할 수 없습니다. 지정하지 않아 죄송합니다. 그리고 @Lasse, 나는 동의 할 것이고 아마도 동적을 많이 사용하지 않을 것입니다.
Brian Mains

1
최후의 사용 사례는 설명되어 있지 않습니다
denfromufa

1

나를 위해 '동적'유형 변수의 가장 좋은 사용 사례는 최근 ADO.NET에서 데이터 액세스 계층을 작성하고 ( SQLDataReader 사용 ) 코드가 이미 작성된 레거시 저장 프로 시저를 호출 했을 때였습니다 . 대량의 비즈니스 로직을 포함하는 수백 가지의 레거시 저장 프로 시저가 있습니다. 내 데이터 액세스 계층은 일종의 구조화 된 데이터를 C # 기반의 비즈니스 로직 계층으로 반환하여 약간의 조작을 수행해야했습니다 ( 거의 아무것도 없음 ). 모든 저장 프로시 저는 서로 다른 데이터 집합 ( 테이블 열 )을 반환합니다 . 따라서 반환 된 데이터를 보유하고 BLL에 전달하는 수십 개의 클래스 또는 구조체를 만드는 대신 아래 코드를 작성하여 매우 우아하고 깔끔합니다.

public static dynamic GetSomeData(ParameterDTO dto)
        {
            dynamic result = null;
            string SPName = "a_legacy_stored_procedure";
            using (SqlConnection connection = new SqlConnection(DataConnection.ConnectionString))
            {
                SqlCommand command = new SqlCommand(SPName, connection);
                command.CommandType = System.Data.CommandType.StoredProcedure;                
                command.Parameters.Add(new SqlParameter("@empid", dto.EmpID));
                command.Parameters.Add(new SqlParameter("@deptid", dto.DeptID));
                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        dynamic row = new ExpandoObject();
                        row.EmpName = reader["EmpFullName"].ToString();
                        row.DeptName = reader["DeptName"].ToString();
                        row.AnotherColumn = reader["AnotherColumn"].ToString();                        
                        result = row;
                    }
                }
            }
            return result;
        }

0
  1. pythonnet을 사용하여 CPython과 같은 동적 언어를 호출 할 수 있습니다.

dynamic np = Py.Import("numpy")

  1. dynamic숫자 연산자를 적용 할 때 제네릭을 캐스트 할 수 있습니다 . 이것은 형식 안전성을 제공하고 제네릭의 제한을 피합니다. 본질적으로 * 덕 타이핑 :

T y = x * (dynamic)x, 어디 typeof(x) is T


0

dynamic타이핑의 또 다른 사용 사례 는 공분산 또는 반공산에 문제가있는 가상 방법입니다. 그러한 예 중 하나 Clone는 호출 된 객체와 동일한 유형의 객체를 반환하는 악명 높은 메서드입니다. 이 문제는 정적 유형 검사를 우회하기 때문에 동적 반환으로 완전히 해결되지는 않지만 plain을 사용할 때마다 항상 추한 캐스트를 사용할 필요는 없습니다 object. 그렇지 않으면, 캐스트는 내재적으로됩니다.

public class A
{
    // attributes and constructor here
    public virtual dynamic Clone()
    {
        var clone = new A();
        // Do more cloning stuff here
        return clone;
    }
}

public class B : A
{
    // more attributes and constructor here
    public override dynamic Clone()
    {
        var clone = new B();    
        // Do more cloning stuff here
        return clone;
    }
}    

public class Program
{
    public static void Main()
    {
        A a = new A().Clone();  // No cast needed here
        B b = new B().Clone();  // and here
        // do more stuff with a and b
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.