ประเภท 'ไดนามิก' ใน C # 4.0 ใช้เพื่ออะไร


236

C # 4.0 แนะนำประเภทใหม่ที่เรียกว่า 'ไดนามิก' ทุกอย่างฟังดูดี แต่โปรแกรมเมอร์จะใช้อะไร?

มีสถานการณ์ที่สามารถช่วยชีวิตวันได้หรือไม่?



มันมีประโยชน์เมื่อทำงานกับ COM หรือภาษาที่พิมพ์แบบไดนามิก ตัวอย่างเช่นถ้าคุณใช้ lua หรือ python ในการเขียนสคริปต์ภาษาของคุณมันสะดวกมากที่จะโทรไปที่โค้ดสคริปต์ราวกับว่ามันเป็นรหัสปกติ
CodesInChaos


ฉันหวังว่าบทความนี้จะตอบคำถามของคุณได้อย่างสมบูรณ์visualstudiomagazine.com/Articles/2011/02/01/…
นักพัฒนา

คำตอบ:


196

คีย์เวิร์ดไดนามิกนั้นใหม่สำหรับ C # 4.0 และใช้เพื่อบอกคอมไพเลอร์ว่าชนิดของตัวแปรสามารถเปลี่ยนแปลงได้หรือไม่รู้จักจนกระทั่งรันไทม์ คิดว่ามันสามารถโต้ตอบกับวัตถุได้โดยไม่ต้องร่าย

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

แจ้งให้ทราบว่าเราไม่จำเป็นต้องส่งหรือประกาศการเป็นลูกค้าประเภท เนื่องจากเราประกาศว่าเป็นแบบไดนามิกรันไทม์จะเข้าควบคุมและค้นหาและตั้งค่าคุณสมบัติ FirstName สำหรับเรา ตอนนี้แน่นอนเมื่อคุณใช้ตัวแปรแบบไดนามิกคุณกำลังเลิกการตรวจสอบประเภทคอมไพเลอร์ ซึ่งหมายความว่าการเรียก cust.MissingMethod () จะรวบรวมและไม่ล้มเหลวจนกว่ารันไทม์ ผลลัพธ์ของการดำเนินการนี้คือ RuntimeBinderException เนื่องจาก MissingMethod ไม่ได้ถูกกำหนดไว้ในคลาสลูกค้า

ตัวอย่างด้านบนแสดงวิธีการทำงานของไดนามิกเมื่อเรียกใช้เมธอดและคุณสมบัติ คุณลักษณะที่มีประสิทธิภาพ (และอาจเป็นอันตราย) อีกประการหนึ่งคือการสามารถนำตัวแปรมาใช้ใหม่สำหรับข้อมูลประเภทต่างๆ ฉันแน่ใจว่าโปรแกรมเมอร์ Python, Ruby และ Perl ออกไปสามารถคิดได้หลายล้านวิธีในการใช้ประโยชน์จากสิ่งนี้ แต่ฉันใช้ C # มานานจนรู้สึกว่า "ผิด" กับฉัน

dynamic foo = 123;
foo = "bar";

ตกลงดังนั้นคุณมักจะไม่เขียนโค้ดเหมือนด้านบนบ่อยมาก อย่างไรก็ตามอาจมีบางครั้งที่การใช้ซ้ำตัวแปรสามารถใช้งานได้สะดวกหรือทำความสะอาดโค้ดที่สกปรก กรณีง่าย ๆ ที่ฉันพบเจอบ่อยครั้งคือต้องทำการคำนวณระหว่างทศนิยมและทศนิยมสองเท่า

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 และ line 3 ไม่ได้คอมไพล์เพราะ Math.Sqrt ต้องการ double เห็นได้ชัดว่าสิ่งที่คุณต้องทำคือการส่งและ / หรือเปลี่ยนประเภทตัวแปรของคุณ แต่อาจมีสถานการณ์ที่การใช้แบบไดนามิกเหมาะสม

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
โดยส่วนตัวแล้วฉันไม่ชอบความคิดในการใช้dynamicin # ในการแก้ปัญหาที่สามารถแก้ไขได้ (อาจจะดีกว่า) โดยคุณสมบัติมาตรฐาน c # และการพิมพ์แบบสแตติกหรืออย่างมากกับการอนุมานประเภท ( var) dynamicควรเพียง แต่นำมาใช้เมื่อมันมาถึงประเด็น interoperabilty กับ DLR หากคุณเขียนโค้ดในภาษาที่พิมพ์แบบคงที่เช่น c # คือให้ทำและไม่เลียนแบบภาษาแบบไดนามิก นั่นเป็นเพียงน่าเกลียด
Philip Daubmeier

40
หากคุณใช้ประโยชน์จากdynamicตัวแปรจำนวนมากในรหัสของคุณซึ่งคุณไม่ต้องการตัวแปรเหล่านั้น (เช่นในตัวอย่างของคุณกับ squareroot) คุณจะต้องตรวจสอบข้อผิดพลาดในการคอมไพล์เวลาคอมไพล์ แทนตอนนี้คุณได้รับข้อผิดพลาด runtime ที่เป็นไปได้
Philip Daubmeier

33
ส่วนใหญ่ดี แต่ข้อผิดพลาดเล็กน้อย อันดับแรกไม่ถูกต้องที่จะบอกว่าไดนามิกหมายความว่าชนิดของตัวแปรสามารถเปลี่ยนแปลงได้ ตัวแปรที่เป็นปัญหาคือประเภท "ไดนามิก" (จากมุมมองของภาษา C # จากมุมมองของ CLR ตัวแปรเป็นประเภทวัตถุ) ชนิดของตัวแปรไม่เคยเปลี่ยนแปลง ชนิดรันไทม์ของค่าของตัวแปรสามารถเป็นชนิดใด ๆ ที่เข้ากันได้กับชนิดของตัวแปร (หรือในกรณีประเภทอ้างอิงอาจเป็นโมฆะ)
Eric Lippert

15
เกี่ยวกับประเด็นที่สองของคุณ: C # มีคุณสมบัติของ "สร้างตัวแปรที่คุณสามารถใส่อะไรก็ได้" - คุณสามารถสร้างตัวแปรประเภทวัตถุได้เสมอ สิ่งที่น่าสนใจเกี่ยวกับไดนามิกคือสิ่งที่คุณชี้ให้เห็นในย่อหน้าแรกของคุณ: ไดนามิกนั้นใกล้เคียงกับวัตถุยกเว้นว่าการวิเคราะห์ความหมายจะเลื่อนออกไปจนกระทั่งรันไทม์และการวิเคราะห์เชิงความหมายจะทำในประเภทไทม์ของนิพจน์ (ส่วนใหญ่มีข้อยกเว้นบางอย่าง)
Eric Lippert

18
ฉันได้ใช้คะแนน downvote ในเรื่องนี้เป็นหลักเพราะมันเป็นการสนับสนุนการใช้คำหลักสำหรับการใช้งานทั่วไป มันมีวัตถุประสงค์เฉพาะเจาะจง (อธิบายอย่างสมบูรณ์ในคำตอบของ Lasses) และถึงแม้ว่าคำตอบนี้จะถูกต้องทางเทคนิค แต่ก็มีแนวโน้มที่จะนำไปสู่นักพัฒนาที่หลงผิด
Eight-Bit Guru

211

dynamicคำหลักที่ถูกเพิ่มเข้ามาพร้อมกับคุณสมบัติใหม่อื่น ๆ ของ C # 4.0 ที่จะทำให้มันง่ายที่จะพูดคุยกับรหัสที่อาศัยอยู่ในหรือมาจากเวลาการทำงานอื่น ๆ ที่มี APIs ที่แตกต่างกัน

ลองยกตัวอย่าง

หากคุณมีวัตถุ 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);

หมายเหตุข้อโต้แย้งเหล่านั้นทั้งหมดหรือไม่ คุณต้องผ่านสิ่งเหล่านี้ตั้งแต่ C # ก่อนเวอร์ชัน 4.0 ไม่มีความคิดเห็นเกี่ยวกับอาร์กิวเมนต์ที่เป็นทางเลือก ใน C # 4.0 นั้น COM APIs สามารถทำงานได้ง่ายขึ้นโดยแนะนำ:

  1. อาร์กิวเมนต์ตัวเลือก
  2. การสร้างrefทางเลือกสำหรับ COM APIs
  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 ชอบที่จะบอกว่าคุณต้องเรียกใช้ "คาถา" ที่แตกต่างกันซึ่งเป็นการเรียงความของปุนเกี่ยวกับความมหัศจรรย์ของสิ่งทั้งปวงโดยทั่วไปคุณจะต้องโบกมือของคุณและพูดคำวิเศษในลำดับที่ถูกต้อง เพื่อให้ได้คาถาบางประเภท วิธี API แบบเก่าในการพูดคุยกับวัตถุ COM นั้นมีมากมายคุณต้องข้ามหลาย ๆ วงเพื่อที่จะเกลี้ยกล่อมคอมไพเลอร์เพื่อรวบรวมรหัสให้คุณ

สิ่งต่าง ๆ ใน C # ก่อนเวอร์ชัน 4.0 ยิ่งถ้าคุณพยายามพูดคุยกับวัตถุ COM ที่คุณไม่มีอินเทอร์เฟซหรือคลาสสำหรับสิ่งที่คุณมีคือการIDispatchอ้างอิง

หากคุณไม่รู้ว่ามันคือIDispatchอะไรโดยทั่วไปจะสะท้อนวัตถุ COM ด้วยIDispatchอินเทอร์เฟซคุณสามารถถามวัตถุ "หมายเลข id สำหรับวิธีการที่รู้จักกันในชื่อ" คืออะไรและสร้างอาร์เรย์บางประเภทที่มีค่าอาร์กิวเมนต์และในที่สุดก็เรียกInvokeวิธีการบนIDispatchอินเตอร์เฟซเพื่อเรียกวิธีการผ่านทั้งหมด ข้อมูลที่คุณจัดการเพื่อขโมยด้วยกัน

วิธีการบันทึกข้างต้นอาจมีลักษณะเช่นนี้ (นี่ไม่ใช่รหัสที่ถูกต้อง):

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ถ้าคุณต้องการอ่านเพิ่มเติมเกี่ยวกับมัน มันเต็มไปด้วยเลือด

อย่างไรก็ตามถ้าคุณต้องการคุยกับวัตถุ Python ล่ะ? มี API ที่แตกต่างจากที่ใช้กับวัตถุ COM และเนื่องจากวัตถุ Python นั้นเป็นแบบไดนามิกในธรรมชาติเช่นกันคุณต้องหันกลับไปใช้เวทมนตร์เพื่อค้นหาวิธีการที่เหมาะสมในการเรียกพารามิเตอร์ของพวกมันเป็นต้น แต่ไม่ใช่. NET การไตร่ตรองสิ่งที่เขียนสำหรับ Python ค่อนข้างคล้ายกับรหัส IDispatch ด้านบนแตกต่างกันโดยสิ้นเชิง

และสำหรับทับทิม? API อื่นยังคง

JavaScript? ข้อตกลงเดียวกัน API ที่แตกต่างกันเช่นกัน

คำหลักแบบไดนามิกประกอบด้วยสองสิ่ง:

  1. คำหลักใหม่ใน C # dynamic
  2. ชุดของคลาสรันไทม์ที่รู้วิธีจัดการกับออบเจ็กต์ประเภทต่างๆที่ใช้ API เฉพาะที่dynamicคำหลักต้องการและแมปการโทรไปในทางที่ถูกต้องในการทำสิ่งต่าง ๆ API ยังมีการจัดทำเป็นเอกสารดังนั้นหากคุณมีวัตถุที่มาจากรันไทม์ที่ไม่ครอบคลุมคุณสามารถเพิ่มได้

อย่างไรก็ตามdynamicคำหลักนั้นไม่ได้หมายถึงการแทนที่รหัสใด ๆ . NET ที่มีอยู่เท่านั้น แน่นอนว่าคุณสามารถทำได้ แต่มันไม่ได้ถูกเพิ่มเข้ามาด้วยเหตุผลนั้นและผู้เขียนภาษา C # ที่มี Anders Hejlsberg อยู่ข้างหน้านั้นเป็นคนที่ยืนกรานว่าพวกเขายังคงมองว่า C # เป็นภาษาที่พิมพ์ออกมารุนแรงและจะไม่เสียสละ หลักการนั้น

ซึ่งหมายความว่าแม้ว่าคุณจะสามารถเขียนโค้ดแบบนี้ได้:

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

และมันได้รวบรวมมันไม่ได้หมายความว่าเป็นประเภทของระบบมายากลช่วยให้คิดออกสิ่งที่คุณหมายถึงที่รันไทม์ของระบบ

จุดประสงค์ทั้งหมดคือเพื่อให้ง่ายต่อการพูดคุยกับวัตถุประเภทอื่น

มีเนื้อหามากมายบนอินเทอร์เน็ตเกี่ยวกับคำหลักผู้เสนอฝ่ายตรงข้ามการสนทนาการยกย่องสรรเสริญ ฯลฯ

ฉันขอแนะนำให้คุณเริ่มต้นด้วยลิงก์ต่อไปนี้และจากนั้น google เพื่อเพิ่มเติม:


12
นอกจากนี้ยังมีประโยชน์นอกเหนือจาก COM สำหรับเว็บ JSON API ที่โครงสร้างของออบเจ็กต์ JSON แบบไม่ต่อเนื่องไม่ได้ระบุไว้ใน C # ยกตัวอย่างเช่นSystem.Web.Helpers.Jsonวิธี 's ถอดรหัสผลตอบแทนวัตถุแบบไดนามิก
dumbledad

ข้อยกเว้นเกี่ยวกับ "พวกเขายังถือว่า C # เป็นภาษาที่พิมพ์อย่างรุนแรง": Eric Lippert ไม่ได้เป็นแฟนของ "พิมพ์อย่างยิ่ง"เป็นคำอธิบาย
Andrew Keeton

ฉันไม่เห็นด้วยกับเขา แต่มันเป็นเรื่องของความเห็นไม่ใช่เรื่องจริง "พิมพ์อย่างมาก" สำหรับฉันหมายความว่าคอมไพเลอร์รู้ ณ เวลารวบรวมซึ่งเป็นประเภทที่ใช้และบังคับใช้กฎที่ตั้งไว้รอบ ๆ ประเภทเหล่านั้น ความจริงที่ว่าคุณสามารถเลือกประเภทไดนามิกที่เลื่อนการตรวจสอบกฎและการเชื่อมโยงกับรันไทม์ไม่ได้สำหรับฉันหมายความว่าภาษานั้นพิมพ์ได้อย่างอ่อน ฉันมักจะไม่แตกต่างกันอย่างมากกับการพิมพ์ที่อ่อนแอ แต่ฉันมักจะเปรียบเทียบกับการพิมพ์แบบไดนามิกเช่นภาษาเช่น Python ที่ทุกอย่างเป็นเป็ดจนกว่ามันจะเห่า
Lasse V. Karlsen

ประเด็นของคำตอบนี้คืออะไร? ครึ่งหนึ่งเป็นเรื่องของพารามิเตอร์ทางเลือกและส่วนต่อประสาน IDispatch
Xam

นั่นคือเหตุผลที่dynamicถูกเพิ่มเข้ามาเพื่อสนับสนุนระบบนิเวศอื่น ๆ สำหรับวิธีการเรียกใช้เมธอดคล้ายภาพสะท้อนรวมถึงการจัดทำกล่องดำเรียงลำดับโครงสร้างข้อมูลด้วยวิธีการบันทึกเอกสารเพื่อให้บรรลุเป้าหมายนี้
Lasse V. Karlsen

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คือ subclass ของMapPointและถ้ามันไม่ได้ถูกวางไว้ก่อนที่ MapPointมันจะไม่สามารถเข้าถึงได้ นี่ไม่ใช่กรณีที่มีไดนามิกเนื่องจากวิธีการจับคู่ที่ใกล้เคียงที่สุดจะถูกเรียก

อย่างที่คุณอาจเดาได้จากโค้ดคุณลักษณะนั้นมีประโยชน์ในขณะที่ฉันกำลังทำการแปลจากออบเจ็กต์ ChartItem ไปเป็นเวอร์ชั่นที่ต่อเนื่องกันได้ ฉันไม่ต้องการทำให้รหัสของฉันสกปรกกับผู้เยี่ยมชมและฉันก็ไม่ต้องการทำให้ChartItemวัตถุของฉันสกปรกด้วยคุณลักษณะเฉพาะที่ทำให้เป็นอนุกรม


ไม่ทราบเกี่ยวกับกรณีการใช้งานนี้ แม้ว่าจะแฮ็คบิตที่ดีที่สุด มันจะทิ้งวิเคราะห์แบบคงที่ใด ๆ ออก
Kugel

2
@ Kugel นั้นเป็นเรื่องจริง แต่ฉันจะไม่เรียกมันว่าแฮ็ค การวิเคราะห์แบบสแตติกนั้นดี แต่ฉันจะไม่ยอมให้มันป้องกันฉันจากวิธีการแก้ปัญหาที่สง่างามซึ่งทางเลือกคือ: การละเมิดหลักการแบบเปิดปิด (รูปแบบผู้เข้าชม) หรือความซับซ้อนisของวงจรที่เพิ่มขึ้น
Stelios Adamantidis

4
คุณมีรูปแบบการจับคู่กับ C # 7 ได้หรือไม่
Kugel

2
ผู้ประกอบการก็มีราคาถูกกว่ามาก (หลีกเลี่ยงการโยนคู่) และคุณได้รับการวิเคราะห์แบบคงที่กลับมา ;-) และประสิทธิภาพ
Kugel

@idbrii โปรดอย่าเปลี่ยนคำตอบของฉัน รู้สึกอิสระที่จะส่งความคิดเห็นและฉันจะชี้แจง (ถ้าจำเป็น) เพราะฉันยังคงใช้งานในชุมชนนี้ นอกจากนี้โปรดอย่าใช้magic; ไม่มีสิ่งใดที่เป็นเวทย์มนตร์
Stelios Adamantidis

11

มันทำให้ง่ายขึ้นสำหรับภาษาที่พิมพ์แบบคงที่ (CLR) เพื่อทำงานร่วมกับภาษาแบบไดนามิก (หลาม, ทับทิม ... ) ที่ทำงานบน DLR (รันไทม์ภาษาแบบไดนามิก), ดูMSDN :

ตัวอย่างเช่นคุณอาจใช้รหัสต่อไปนี้เพื่อเพิ่มตัวนับใน XML ใน C #

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

โดยใช้ DLR คุณสามารถใช้รหัสต่อไปนี้แทนการดำเนินการเดียวกัน

scriptobj.Count += 1;

MSDN แสดงข้อดีเหล่านี้:

  • ลดความยุ่งยากในการย้ายภาษาไดนามิกไปยัง. NET Framework
  • เปิดใช้งานคุณสมบัติแบบไดนามิกในภาษาที่พิมพ์แบบคงที่
  • ให้ประโยชน์ในอนาคตของ DLR และ. NET Framework
  • เปิดใช้งานการแชร์ไลบรารีและวัตถุ
  • จัดส่ง Fast Dynamic และการเรียกใช้

ดูMSDNสำหรับรายละเอียดเพิ่มเติม


1
และการเปลี่ยนแปลงที่เขาต้องการสำหรับไดนามิกทำให้ภาษาไดนามิกง่ายขึ้น
Dykam

2
@Dykam: ไม่มีการเปลี่ยนแปลง VM DLR ใช้งานได้ดีไปจนถึง. NET 2.0
Jörg W Mittag

@ Jörgใช่มีการเปลี่ยนแปลง DLR ถูกเขียนใหม่บางส่วนเพราะตอนนี้ VM มีโครงสร้างที่รองรับการแก้ไขแบบไดนามิก
Dykam

ฉันมองโลกในแง่ดีเกินไปการวิจัยแสดงให้เห็นว่าการเปลี่ยนแปลงไม่ได้ใหญ่ขนาดนั้น
Dykam

4

ตัวอย่างการใช้งาน:

คุณใช้หลายคลาสที่มีคุณสมบัติชุมชน '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' คุณจะต้องใช้การสะท้อน:

    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 โดยเฉพาะอย่างยิ่ง IUnknown มันถูกออกแบบมาเป็นพิเศษสำหรับมัน


2

ส่วนใหญ่มันจะถูกใช้โดยผู้ที่ตกเป็นเหยื่อ RAD และ Python เพื่อทำลายคุณภาพของรหัส, IntelliSenseและการตรวจจับข้อผิดพลาดในการรวบรวมเวลา


คำตอบเหยียดหยาม แต่จริงเกินไปง่าย ฉันได้เห็นมันทำเพียงเพื่อหลีกเลี่ยงการประกาศ structs ด้วยผลลัพธ์ที่ว่ารหัสทำงานได้ถ้าทุกอย่างดี แต่พัดสแต็คในรูปแบบที่ไม่สามารถคาดเดาได้ทันทีที่คุณย้ายมันเป็นชีส
AnthonyVO

ใช่คุณจะเห็นว่ามุมคลาสสิกตัดกับคุณสมบัติภาษาอื่น ๆ อีกมากมาย ไม่น่าแปลกใจเลยที่คุณจะได้เห็นที่นี่
Hawkeye4040

1

มันประเมินที่รันไทม์ดังนั้นคุณสามารถสลับชนิดอย่างที่คุณสามารถทำได้ใน JavaScript เป็นสิ่งที่คุณต้องการ นี่คือ Legit:

dynamic i = 12;
i = "text";

และเพื่อให้คุณสามารถเปลี่ยนประเภทตามที่คุณต้องการ ใช้เป็นทางเลือกสุดท้าย มันมีประโยชน์ แต่ฉันได้ยินมาหลายเรื่องในแง่ของการสร้าง IL และมันอาจมาในราคาแสดง


7
ฉันจะลังเลที่จะบอกว่ามันเป็น "Legit" มันจะรวบรวมแน่นอนดังนั้นจึงเป็น "รหัส legit" ในแง่ที่ว่าคอมไพเลอร์จะรวบรวมและรันไทม์จะรัน แต่ฉันไม่ต้องการเห็นรหัสชิ้นใดชิ้นหนึ่ง (หรือบางอย่างที่คล้ายกัน) ในรหัสใด ๆ ที่ฉันรักษาไว้หรือจะเป็นการกระทำที่ใกล้เข้ามา
Lasse V. Karlsen

6
แน่นอน แต่นั่นน่าจะเป็น "legit" กับ "object" แทน "dynamic" คุณไม่ได้แสดงอะไรน่าสนใจเกี่ยวกับไดนามิกที่นี่
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. คุณสามารถโทรเป็นภาษาไดนามิกเช่น CPython โดยใช้ pythonnet:

dynamic np = Py.Import("numpy")

  1. คุณสามารถส่งข้อมูลทั่วไปdynamicเมื่อใช้ตัวดำเนินการตัวเลขกับพวกเขา สิ่งนี้ให้ความปลอดภัยประเภทและหลีกเลี่ยงข้อ จำกัด ของข้อมูลทั่วไป นี่คือสาระสำคัญ * การพิมพ์เป็ด:

T y = x * (dynamic)xที่ไหน typeof(x) is T


0

กรณีการใช้งานอื่นสำหรับการdynamicพิมพ์เป็นวิธีการเสมือนที่ประสบปัญหาความแปรปรวนร่วมหรือความแปรปรวน ตัวอย่างหนึ่งคือCloneวิธีการที่น่าอับอายที่ส่งคืนวัตถุประเภทเดียวกันกับวัตถุที่ถูกเรียกใช้ ปัญหานี้ไม่ได้รับการแก้ไขอย่างสมบูรณ์ที่มีผลตอบแทนแบบไดนามิกเพราะมันทะลุตรวจสอบประเภทคงที่ 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.