วิธีเพิ่มผู้รับมอบสิทธิ์ในอินเทอร์เฟซ C #


95

ฉันต้องมีผู้ร่วมประชุมบางคนในชั้นเรียนของฉัน

ฉันต้องการใช้อินเทอร์เฟซเพื่อ "เตือน" ให้ตั้งค่าผู้รับมอบสิทธิ์เหล่านี้

ทำอย่างไร?

ชั้นเรียนของฉันมีลักษณะดังนี้:

public class ClsPictures : myInterface
{
    // Implementing the IProcess interface
    public event UpdateStatusEventHandler UpdateStatusText;
    public delegate void UpdateStatusEventHandler(string Status);

    public event StartedEventHandler Started;
    public delegate void StartedEventHandler();
}

ฉันต้องการอินเทอร์เฟซเพื่อบังคับให้ผู้รับมอบสิทธิ์เหล่านั้น:

public interface myInterface
{
   // ?????
}

คำตอบ:


144

เหล่านี้จะประกาศผู้รับมอบสิทธิ์ประเภท พวกเขาไม่ได้อยู่ในอินเทอร์เฟซ เหตุการณ์ที่ใช้ประเภทผู้รับมอบสิทธิ์เหล่านั้นสามารถอยู่ในอินเทอร์เฟซได้แม้ว่า:

public delegate void UpdateStatusEventHandler(string status);
public delegate void StartedEventHandler();

public interface IMyInterface
{       
    event UpdateStatusEventHandler StatusUpdated;    
    event StartedEventHandler Started;
}

การใช้งานจะไม่ (และไม่ควร) ประกาศประเภทผู้รับมอบสิทธิ์ซ้ำมากกว่าที่จะประกาศประเภทอื่น ๆ ที่ใช้ในอินเทอร์เฟซ


แค่นี้ก็ไม่ได้ผลสำหรับฉัน ฉันมั่นใจว่าฉันได้ทำทุกอย่างแล้ว แต่ตัวจัดการของฉันในอินเทอร์เฟซของฉันไม่ได้รับการยอมรับ คลาสของฉันที่ใช้อินเทอร์เฟซกำลังบ่นว่าคลาสไม่ตรงกับประเภทการส่งคืนอินเทอร์เฟซของ System.EventHandler
Chucky

1
@ ชัคกี้: ดูเหมือนว่าคุณควรถามคำถามใหม่ด้วยตัวอย่างสั้น ๆ แต่สมบูรณ์เพื่อสาธิตปัญหา คำตอบที่ฉันให้ไว้ใช้งานได้จริง
Jon Skeet

4
ฉันไม่ทราบว่าผู้ได้รับมอบหมายมีการเข้าถึงระดับเดียวกับชั้นเรียน ฉันคิดเสมอว่าพวกเขาต้องถูกห่อหุ้มภายในชั้นเรียน
ปุรุสสาธะ

7
@Purusartha: นั่นไม่ใช่การเข้าถึง - นั่นเป็นเพียงเรื่องของผู้ได้รับมอบหมายที่เป็นประเภท (ในความเป็นจริงชั้นเรียน) เช่นเดียวกับอินเทอร์เฟซเป็นต้น
Jon Skeet

33

ตั้งแต่. NET 3.5 คุณยังสามารถใช้ผู้รับมอบสิทธิ์ System.Action ได้โดยไม่จำเป็นต้องประกาศประเภทของคุณเอง

ซึ่งจะส่งผลให้เกิดอินเทอร์เฟซต่อไปนี้:

public interface myInterface
{       
   // Implementing the IProcess interface
   event Action<String> UpdateStatusText;

   event Action Started;
}

1
+1. ฉันพบว่า Action / Func มีความหรูหรา (และอ่านได้) มากกว่าประเภทผู้รับมอบสิทธิ์แบบเดิมและคุณสามารถกำหนดได้ในอินเทอร์เฟซ
chrnola

2
คำตอบนี้ไม่ได้ตอบคำถาม (วิธีใช้ myInterface)
lharper71

11

เพียงแค่เปิดเผยผู้รับมอบสิทธิ์เป็นทรัพย์สิน

public delegate void UpdateStatusEventHandler(string status);
public delegate void StartedEventHandler();

public interface IMyInterface
{       
    UpdateStatusEventHandler StatusUpdated {get; set;}    
    StartedEventHandler Started {get; set;}
}

7

คำตอบของ Jon Skeet ถูกต้องฉันแค่อยากจะเพิ่มโน้ต

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

หากคุณต้องการบังคับใช้มาตรฐานการเข้ารหัสบางอย่างในโปรเจ็กต์ของคุณคุณอาจต้องการลองใช้เครื่องมือวิเคราะห์โค้ด (เช่นใน Visual Studio) ซึ่งอนุญาตให้มีส่วนขยายที่คุณสามารถรวมเข้าด้วยกันเพื่อเพิ่มกฎการวิเคราะห์โค้ดของคุณเอง

การใช้การวิเคราะห์รหัสหากคุณ "ลืม" เพื่อเพิ่มผู้รับมอบสิทธิ์ (แม้ว่าฉันจะไม่เห็นจุดที่จะลืมมันราวกับว่าไม่ได้ใช้ผู้รับมอบสิทธิ์ก็ไม่จำเป็น) คุณจะได้รับคำเตือน / ข้อผิดพลาด


1
คุณอาจจะพูดถูก แต่มีบางครั้งที่คุณตั้งสมมติฐานว่าแม้จะมีเอกสารที่ดี แต่ก็ยากที่จะจดจำหลังจากนั้นสักครู่ ฉันพยายามใช้รหัสของฉันซ้ำ แต่บางครั้งฉันจำไม่ได้ว่ามันเป็นแกนหลักอะไรและไม่ใช่อะไร (เมื่อพูดถึงผู้ได้รับมอบหมาย - มันยากสำหรับฉันที่จะเห็นภาพรวม ... )
Asaf

1

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

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

ชั้นเรียนของคุณจะมีลักษณะดังนี้:

public class ClsPictures : myInterface
{
    // Implementing the IProcess interface
    public event EventHandler<UpdateStatusEventArgs> UpdateStatusText;
    //no need for this anymore: public delegate void UpdateStatusEventHandler(string Status);

    public event EventHandler<StartedEventArgs> Started;
    //no need for this anymore: public delegate void StartedEventHandler();
}

อินเทอร์เฟซของคุณจะมีลักษณะดังนี้:

public interface myInterface
{
   event EventHandler<StartedEventArgs> Started;
   event EventHandler<UpdateStatusEventArgs> UpdateStatusText;
}

ตอนนี้อาร์กิวเมนต์ของเหตุการณ์กำลังส่งคืนประเภทของคุณคุณสามารถเชื่อมต่อกับตัวจัดการที่คุณกำหนด

สำหรับการอ้างอิง: https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx


0

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

แต่คุณอาจต้องการใช้อย่างชัดเจนและคุณยังคงต้องเชื่อมโยงกับวัตถุ

ตัวอย่างเช่นการใช้รูปแบบการควบคุมแบบผกผัน:

class Form1 : Form, IForm {
   public Form1() {
     Controls.Add(new Foo(this));
   }

   // Required to be defined here.
   void IForm.Button_OnClick(object sender, EventArgs e) {
     ...
     // Cast qualifier expression to 'IForm' assuming you added a property for StatusBar.
     //((IForm) this).StatusBar.Text = $"Button clicked: ({e.RowIndex}, {e.SubItem}, {e.Model})";
   }
 }

คุณสามารถลองสิ่งนี้

interface IForm {
  void Button_OnClick(object sender, EventArgs e);
}


class Foo : UserControl {
  private Button btn = new Button();

  public Foo(IForm ctx) {
     btn.Name = "MyButton";
     btn.ButtonClick += ctx.Button_OnClick;
     Controls.Add(btn);
  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.