سؤال

في جيسي الحرية البرمجة C# (p.142) كان مثالا حيث كان يلقي كائن إلى الواجهة.

 interface IStorable
 {
    ...
 }

 public class Document : IStorable
 {
    ...
 }

 ...
 IStorable isDoc = (IStorable) doc;  
 ...

ما هو الهدف من هذا لا سيما إذا كان الكائن فئة تنفذ inteface على أية حال ؟

EDIT1:للتوضيح أنا مهتم في السبب المدلى بها (إن وجدت), لا والسبب في تنفيذ الواجهات.أيضا ، في كتاب له عام 2001 الطبعة الأولى (على أساس C#1 لذلك على سبيل المثال قد لا تكون وجيهة أجل والإصدارات اللاحقة من C#).

EDIT2:أضفت بعض السياق إلى رمز

هل كانت مفيدة؟

المحلول

وهناك سبب واحد فقط عندما تحتاجها في الحقيقة يلقي: عندما وثيقة من نوع قاعدة كائن الفعلية التي تطبق IStorable. اسمحوا لي أن أشرح:

public class DocBase
{
  public virtual void DoSomething()
  {

  }
}

public class Document : DocBase, IStorable
{
  public override void DoSomething()
  {
    // Some implementation
    base.DoSomething();
  }

  #region IStorable Members

  public void Store()
  {
    // Implement this one aswell..
    throw new NotImplementedException();
  }

  #endregion
}

public class Program
{
  static void Main()
  {
    DocBase doc = new Document();
    // Now you will need a cast to reach IStorable members
    IStorable storable = (IStorable)doc;
  }
}

public interface IStorable
{
  void Store();
}

نصائح أخرى

ولأنك تريد أن تقيد نفسك إلى أساليب الوحيدة التي قدمت من قبل واجهة. إذا كنت تستخدم الطبقة، كنت عرضة لخطر من استدعاء أسلوب (عن غير قصد) هذا ليس جزءا من واجهة.

إذا الكائن بتطبيق واجهة بشكل واضح (public void IStorable.StoreThis(...)) أن الصب هو أسهل طريقة للوصول إلى الواقع أعضاء الواجهة.

وأنا لست متأكدا تحت أي سياق أعطيت المثال في الكتاب. ولكن، بشكل عام يمكن اكتب يلقي كائن إلى واجهة لتحقيق وراثة متعددة. لقد أعطيت المثال أدناه.

public interface IFoo
{
     void Display();
}
public interface IBar
{
     void Display();
}

public class MyClass : IFoo, IBar
{
    void IBar.Display()
    {
        Console.WriteLine("IBar implementation");
    }
    void IFoo.Display()
    {
        Console.WriteLine("IFoo implementation");
    }
}

public static void Main()
{
    MyClass c = new MyClass();
    IBar b = c as IBar;
    IFoo f = c as IFoo;
    b.Display();
    f.Display();
    Console.ReadLine();
}

وهذا من شأنه أن يعرض

<اقتباس فقرة>   

وإيبار تنفيذ
  تنفيذ IFoo

من الصعب جدا أن أقول دون أكثر من سياق.إذا كان المتغير doc وأعلن أن تكون من النوع التي تطبق الواجهة ، ثم يلقي زائدة عن الحاجة.

إصدار كتاب تقرأ ؟ إذا كان "البرمجة C# 3.0" سألقي نظرة الليلة عندما أكون في المنزل.

تحرير:كما رأينا في إجابات حتى الآن هناك ثلاثة أسئلة محتملة هنا:

  • لماذا يلقي في البيان المبين في السؤال ؟ (الجواب:ليس عليك إذا doc هو مناسب وقت التحويل البرمجي نوع)
  • لماذا من أي وقت مضى المناسبة صراحة يلقي إلى تنفيذ واجهة أو قاعدة الفصل ؟ (الجواب:صريحة واجهة التنفيذ كما هو مبين في جواب آخر ، و أيضا من أجل اختيار أقل تحديدا الزائد عند تمرير يلقي قيمة حجة.)
  • لماذا استخدام واجهة على الإطلاق ؟ (الجواب:العمل مع واجهة نوع يعني أنك أقل عرضة للتغيرات في الخرسانة نوع في وقت لاحق.)

وربما يكون الكائن doc من النوع الذي ينفذ أعضاء IStorable صراحة، وليس إضافتها إلى الواجهة الأساسية الطبقات (أي أنها لا يمكن إلا أن يسمى من خلال واجهة).

والواقع "الصب" (باستخدام بناء الجملة (T)) لا يجعل أي معنى منذ C # يعالج upcasts (يلقي إلى نوع الأصل) تلقائيا (على عكس F # على سبيل المثال).

هناك الكثير من إجابات جيدة هنا, ولكن أنا حقا لا أعتقد أنها إجابة لماذا كنت فعلا تريد أن الاستخدام الأكثر تقييدا واجهة ممكن.

الأسباب لا تنطوي الأولي الخاص بك الترميز ، فإنها تنطوي في المرة القادمة التي تزور أو ريفاكتور رمز أو عند شخص آخر يفعل ذلك.

دعونا نقول كنت ترغب في زر و يتم وضعها على الشاشة.كنت تحصل على الزر إما مرت في أو من خلال وظيفة أخرى, مثل هذا:

Button x=otherObject.getVisibleThingy();
frame.add(x);

كنت أعرف أن VisibleThingy هو زر بإرجاع زر, لذلك كل ما هو رائع هنا (لا يلقي المطلوبة).

الآن, دعونا نقول أنك ريفاكتور VisibleThingy للعودة زر تبديل بدلا من ذلك.لديك الآن ريفاكتور الأسلوب الخاص بك لأنك يعرف الكثير عن التنفيذ.

منذ كنت في حاجة إلى أساليب في العنصر (والد كل من زر تبديل ، والتي يمكن أن يكون واجهة نفس الشيء تقريبا لأغراضنا) ، إذا كنت قد كتبت هذا السطر الأول من هذا القبيل:

Component x=(Component)otherObject.getVisibleThingy();

لن تضطر إلى ريفاكتور أي شيء قد عملت فقط.

هذا هو بسيط جدا الحالة ، ولكن يمكن أن يكون أكثر تعقيدا من ذلك بكثير.

لذا أعتقد الموجز أن واجهة هو طريقة معينة إلى "عرض" وجوه الخاص بك--مثل النظر في ذلك خلال مرشح...يمكنك ان ترى فقط بعض الأجزاء.إذا كنت يمكن أن تحد من الرؤية بما فيه الكفاية ، الكائن يمكن أن "مورف" وراء نظر معينة لا تؤثر على أي شيء في العالم الحالي--قوية جدا خدعة من التجريد.

وأفضل سبب لماذا كنت يلقي إلى واجهات سيكون إذا كنت كتابة التعليمات البرمجية ضد الأشياء وكنت لا تعرف ما هو نوع ملموس هم وكنت لا ترغب في ذلك.

إذا كنت تعرف أنك قد تأتي عبر كائن الذي يقوم بتنفيذ واجهة معينة هل يمكن بعد ذلك الحصول على القيم من الكائن دون الحاجة إلى معرفة فئة محددة أن هذا الكائن. أيضا، إذا كنت تعرف أن كائن بتنفيذ واجهة معينة، قد أن واجهة تحديد الطرق التي يمكن ان تنفذ إلى اتخاذ إجراءات معينة على الكائن.

وهنا مثال بسيط:

public interface IText
{
   string Text { get; }
}

public interface ISuperDooper
{
   string WhyAmISuperDooper { get; }
}

public class Control
{
   public int ID { get; set; }
}

public class TextControl : Control, IText
{
   public string Text { get; set; }
}

public class AnotherTextControl : Control, IText
{
   public string Text { get; set; }
}

public class SuperDooperControl : Control, ISuperDooper
{
   public string WhyAmISuperDooper { get; set; }
}

public class TestProgram
{
   static void Main(string[] args)
   {
      List<Control> controls = new List<Control>
               {
                   new TextControl
                       {
                           ID = 1, 
                           Text = "I'm a text control"
                       },
                   new AnotherTextControl
                       {
                           ID = 2, 
                           Text = "I'm another text control"
                       },
                   new SuperDooperControl
                       {
                           ID = 3, 
                           WhyAmISuperDooper = "Just Because"
                       }
               };

       DoSomething(controls);
   }

   static void DoSomething(List<Control> controls)
   {
      foreach(Control control in controls)
      {
         // write out the ID of the control
         Console.WriteLine("ID: {0}", control.ID);

         // if this control is a Text control, get the text value from it.
         if (control is IText)
            Console.WriteLine("Text: {0}", ((IText)control).Text);

         // if this control is a SuperDooperControl control, get why
         if (control is ISuperDooper)
            Console.WriteLine("Text: {0}", 
                ((ISuperDooper)control).WhyAmISuperDooper);
      }
   }
}

وسوف يعمل هذا البرنامج قليلا تعطيك الإخراج التالية:

<اقتباس فقرة>   

وID: 1

     

النص: أنا تحكم النص

     

وID: 2

     

النص: أنا السيطرة نص آخر

     

وID: 3

     

النص: فقط لأن

لاحظ أن لم يكن لديك لكتابة أي رمز في طريقة تنفيذ DoSomething التي تتطلب مني أن أعرف أي شيء عن كافة الكائنات كنت أعمل على أن تكون أنواع الكائنات ملموسة. الشيء الوحيد الذي أعرفه هو أنني أعمل على الأشياء التي هي على الأقل مثيل من الفئة التحكم. أنا يمكن بعد ذلك استخدام واجهة لمعرفة ماذا قد يكون لديهم.

وهناك مليون سبب المختلفة التي سوف تأخذ هذا النهج مع الواجهات على الأشياء الخاصة بك لكنه يتيح لك طريقة فضفاضة للوصول إلى الأشياء الخاصة بك دون الحاجة إلى معرفة بالضبط ما هو عليه.

وفكر جميع بطاقات الائتمان في العالم، كل شركة تجعل تلقاء نفسها، واجهة هو نفسه على الرغم من ذلك كل قارئ بطاقة يمكن أن يكون لها بطاقة تمريرها من خلال ذلك أن يتبع المعيار. على غرار استخدام الواجهات.

وكما لوحظ، صب لا لزوم له، وليس من الضروري. ومع ذلك، فإنه هو شكل أكثر وضوحا من الترميز التي من شأنها أن تكون مفيدة للمبتدئين في مساعدة فهمهم.

في الكتب المدرسية التمهيدي، فمن الأفضل أن تتصرف بشكل صريح، بدلا من السماح للcompliler تفعل أشياء ضمنا، التي من شأنها أن تكون أكثر مربكة للمبتدئين.

وو"وثيقة" ليست من نوع "IStorable" لذلك سيكون مربكا للمبتدئين لنرى أن يتم تعيينه إلى isDoc. قبل الصب صراحة، مؤلف (كتاب ورمز) يقول أن وثيقة يمكن مسبوكة إلى كائن IStorable، لكنها ليست هي نفسها ككائن IStorable.

المهم هو كائن (من أين لك هذا؟) قد لا تنفيذ واجهة ، وفي هذه الحالة يتم طرح استثناء والتي يمكن أن تكون اشتعلت التعامل معها.بالطبع يمكنك استخدام "هو" المشغل للتحقق ، و "كما" المشغل أن يلقي بدلا من C-الزهر.

لإتاحة الفرصة لأكبر قدر من فصل بين قطعة من رمز ...

وراجع المقالة التالية للمزيد: واجهات

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top