ในขณะนี้มันยังไม่รองรับโดยผู้รวบรวม Roslyn ...
จนถึงขณะนี้คุณสมบัติส่วนขยายยังไม่เห็นว่ามีค่าเพียงพอที่จะรวมไว้ในมาตรฐาน C # รุ่นก่อนหน้า C # 7และC # 8.0เห็นว่านี่เป็นแชมเปี้ยนข้อเสนอ แต่ยังไม่เปิดตัวส่วนใหญ่เพราะแม้ว่าจะมีการนำไปใช้แล้วพวกเขาต้องการทำให้ถูกต้องตั้งแต่เริ่มต้น
แต่มันจะ ...
มีรายการสมาชิกส่วนขยายในรายการงานC # 7ดังนั้นจึงอาจได้รับการสนับสนุนในอนาคตอันใกล้ สถานะปัจจุบันของสถานที่ให้บริการส่วนต่อขยายสามารถพบได้บนGithub ภายใต้รายการที่เกี่ยวข้อง
อย่างไรก็ตามมีหัวข้อที่มีแนวโน้มมากขึ้นซึ่งก็คือ"ขยายทุกอย่าง"โดยเน้นที่คุณสมบัติโดยเฉพาะอย่างยิ่งและคลาสแบบคงที่หรือฟิลด์
ยิ่งกว่านั้นคุณสามารถใช้วิธีแก้ปัญหา
ตามที่ระบุไว้ในบทความนี้คุณสามารถใช้TypeDescriptor
ความสามารถในการแนบคุณสมบัติกับวัตถุตัวอย่างที่รันไทม์ อย่างไรก็ตามมันไม่ได้ใช้ไวยากรณ์ของคุณสมบัติมาตรฐาน
มันแตกต่างกันเล็กน้อยจากน้ำตาล syntactic เพียงเล็กน้อยเพิ่มความเป็นไปได้ในการกำหนดคุณสมบัติแบบขยายเช่น
string Data(this MyClass instance)
นามแฝงสำหรับวิธีการขยาย
string GetData(this MyClass instance)
เนื่องจากเก็บข้อมูลไว้ในชั้นเรียน
ฉันหวังว่า C # 7 จะให้ส่วนขยายที่โดดเด่นเต็มทุกอย่าง (คุณสมบัติและฟิลด์) อย่างไรก็ตามในจุดนั้นจะมีเวลาบอกเท่านั้น
และอย่าลังเลที่จะมีส่วนร่วมเพราะซอฟต์แวร์แห่งวันพรุ่งนี้จะมาจากชุมชน
อัพเดท: สิงหาคม 2559
ในขณะที่ทีม dotnet เผยแพร่สิ่งใหม่ใน C # 7.0และจากความคิดเห็นของMads Torgensen :
คุณสมบัติส่วนขยาย: เรามีการฝึกงาน (ยอดเยี่ยม!) นำพวกมันไปใช้ในช่วงฤดูร้อนพร้อมกับสมาชิกส่วนขยายอื่น ๆ เรายังคงสนใจในสิ่งนี้ แต่มันเป็นการเปลี่ยนแปลงครั้งใหญ่และเราต้องรู้สึกมั่นใจว่ามันคุ้มค่า
ดูเหมือนว่าคุณสมบัติส่วนขยายและสมาชิกอื่น ๆ ยังคงเป็นผู้สมัครที่ดีที่จะรวมอยู่ในการเปิดตัวในอนาคตของ Roslyn แต่อาจไม่ใช่ 7.0
อัปเดต: พฤษภาคม 2017
สมาชิกส่วนขยายถูกปิดเป็นซ้ำกับปัญหาส่วนขยายทุกอย่างที่ปิดเช่นกัน การสนทนาหลักในความเป็นจริงเกี่ยวกับการขยายประเภทในความหมายกว้าง คุณลักษณะนี้จะติดตามตอนนี้ที่นี่เป็นข้อเสนอและได้ถูกลบออกจาก 7.0 ก้าว
อัปเดต: สิงหาคม 2017 - คุณลักษณะที่เสนอ C # 8.0
แม้ว่ามันจะยังคงเป็นเพียงคุณสมบัติที่เสนอแต่ตอนนี้เรามีมุมมองที่ชัดเจนว่าไวยากรณ์ของมันคืออะไร โปรดทราบว่านี่จะเป็นไวยากรณ์ใหม่สำหรับวิธีการส่วนขยายเช่นกัน:
public interface IEmployee
{
public decimal Salary { get; set; }
}
public class Employee
{
public decimal Salary { get; set; }
}
public extension MyPersonExtension extends Person : IEmployee
{
private static readonly ConditionalWeakTable<Person, Employee> _employees =
new ConditionalWeakTable<Person, Employee>();
public decimal Salary
{
get
{
// `this` is the instance of Person
return _employees.GetOrCreate(this).Salary;
}
set
{
Employee employee = null;
if (!_employees.TryGetValue(this, out employee)
{
employee = _employees.GetOrCreate(this);
}
employee.Salary = value;
}
}
}
IEmployee person = new Person();
var salary = person.Salary;
คล้ายกับคลาสบางส่วน แต่ถูกคอมไพล์เป็นคลาส / ชนิดแยกในแอสเซมบลีที่แตกต่างกัน หมายเหตุคุณจะสามารถเพิ่มสมาชิกแบบคงที่และผู้ประกอบการด้วยวิธีนี้ ดังกล่าวในMads Torgensen พอดคาสต์ , ส่วนขยายจะไม่ได้มีรัฐใด ๆ (ดังนั้นจึงไม่สามารถเพิ่มสมาชิก instance ส่วนตัวในชั้นเรียน) ซึ่งหมายความว่าคุณจะไม่สามารถที่จะเพิ่มข้อมูลส่วนตัวเช่นที่เชื่อมโยงกับอินสแตนซ์ เหตุผลที่เรียกเช่นนั้นก็คือมันจะหมายถึงการจัดการพจนานุกรมภายในและอาจเป็นเรื่องยาก (การจัดการหน่วยความจำ ฯลฯ ... ) สำหรับสิ่งนี้คุณยังสามารถใช้TypeDescriptor
/ ConditionalWeakTable
เทคนิคที่อธิบายไว้ก่อนหน้านี้และด้วยส่วนขยายคุณสมบัติซ่อนไว้ภายใต้คุณสมบัติที่ดี
ไวยากรณ์ยังคงมีการเปลี่ยนแปลงตามนัยปัญหานี้ ตัวอย่างเช่นextends
อาจถูกแทนที่ด้วยfor
ซึ่งบางคนอาจรู้สึกเป็นธรรมชาติมากขึ้นและน้อยกว่าจาวาที่เกี่ยวข้อง
อัปเดตธันวาคม 2561 - บทบาทส่วนขยายและสมาชิกส่วนต่อประสานแบบคงที่
การขยายทุกอย่างไม่ได้ทำให้เป็น C # 8.0 เนื่องจากมีข้อบกพร่องบางอย่างที่อธิบายไว้ในตอนท้ายของตั๋ว GitHubนี้ ดังนั้นจึงมีการสำรวจเพื่อปรับปรุงการออกแบบ ที่นี่ Mads Torgensen อธิบายว่าอะไรคือบทบาทและส่วนขยายและความแตกต่าง:
บทบาทอนุญาตให้อินเตอร์เฟสถูกนำไปใช้กับค่าเฉพาะของชนิดที่กำหนด ส่วนต่อขยายอนุญาตให้มีการใช้งานอินเทอร์เฟซกับค่าทั้งหมดของประเภทที่กำหนดภายในขอบเขตรหัสเฉพาะ
มันสามารถเห็นได้ที่แยกข้อเสนอก่อนหน้าในสองกรณีการใช้งาน ไวยากรณ์ใหม่สำหรับการขยายจะเป็นเช่นนี้
public extension ULongEnumerable of ulong
{
public IEnumerator<byte> GetEnumerator()
{
for (int i = sizeof(ulong); i > 0; i--)
{
yield return unchecked((byte)(this >> (i-1)*8));
}
}
}
จากนั้นคุณจะสามารถทำสิ่งนี้:
foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
WriteLine($"{e.Current:X}");
}
และสำหรับอินเทอร์เฟซแบบคงที่ :
public interface IMonoid<T> where T : IMonoid<T>
{
static T operator +(T t1, T t2);
static T Zero { get; }
}
เพิ่มคุณสมบัติขยายบนint
และรักษาint
เป็นIMonoid<int>
:
public extension IntMonoid of int : IMonoid<int>
{
public static int Zero => 0;
}