কেন সি # ইন্টারফেস পদ্ধতিগুলি বিমূর্ত বা ভার্চুয়াল হিসাবে ঘোষিত হয় না?


108

ইন্টারফেসে সি # পদ্ধতিগুলি virtualকীওয়ার্ডটি ব্যবহার না করে এবং ঘোষিত ক্লাসে কীওয়ার্ডটি ব্যবহার না করেই ঘোষণা করা হয় override

এরজন্য কি কোন কারণ আছে? আমি ধরে নিলাম যে এটি কেবল একটি ভাষার সুবিধার্থে এবং স্পষ্টতই সিএলআর জানে কীভাবে এটি কভারগুলির অধীনে পরিচালনা করতে হয় (পদ্ধতিগুলি ডিফল্টরূপে ভার্চুয়াল নয়) তবে অন্যান্য প্রযুক্তিগত কারণগুলিও রয়েছে?

এখানে প্রাপ্ত আইএল যা একটি উদ্ভূত শ্রেণি উত্পন্ন করে:

class Example : IDisposable {
    public void Dispose() { }
}

.method public hidebysig newslot virtual final 
        instance void  Dispose() cil managed
{
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Example::Dispose

লক্ষ করুন যে পদ্ধতিটি virtual finalআইএল-এ ঘোষণা করা হয়েছে।

উত্তর:


145

ইন্টারফেসের জন্য abstract, যোগ বা এমনকি publicকীওয়ার্ডগুলি অতিরিক্ত কাজ হবে, সুতরাং আপনি এগুলি বাদ দিন:

interface MyInterface {
  void Method();
}

সিআইএলে, পদ্ধতিটি চিহ্নিত করা হয় virtualএবং abstract

(নোট করুন যে জাভা ইন্টারফেস সদস্যদের ঘোষণার অনুমতি দেয় public abstract)।

বাস্তবায়নকারী শ্রেণীর জন্য কিছু বিকল্প রয়েছে:

অ-ওভাররিজেবল : সি # তে শ্রেণিটি পদ্ধতিটি যেমন ঘোষণা করে না virtual। এর অর্থ এটি একটি উদ্ভূত শ্রেণিতে (কেবল লুকানো নয়) ওভাররাইড করা যাবে না। সিআইএলে পদ্ধতিটি এখনও ভার্চুয়াল (তবে সিল করা) কারণ এটি অবশ্যই ইন্টারফেসের প্রকারের ক্ষেত্রে বহুবর্ষ সমর্থন করে।

class MyClass : MyInterface {
  public void Method() {}
}

ওভাররিডেবল : সি # এবং সিআইএল উভয়ই পদ্ধতিটি virtual। এটি পলিমারফিক প্রেরণে অংশ নেয় এবং এটি ওভাররাইড করা যায়।

class MyClass : MyInterface {
  public virtual void Method() {}
}

সুস্পষ্ট : এটি কোনও শ্রেণীর জন্য একটি ইন্টারফেস বাস্তবায়ন করার উপায় তবে ক্লাসের পাবলিক ইন্টারফেসে ইন্টারফেসের পদ্ধতিগুলি সরবরাহ করে না। সিআইএল-এ পদ্ধতিটি private(!) হবে তবে এটি এখনও ইন্টারফেসের প্রকারের রেফারেন্স থেকে শ্রেণির বাইরে থেকে কলযোগ্য হবে। সুস্পষ্ট বাস্তবায়নগুলি অ-ওভাররিডযোগ্য। এটি সম্ভব কারণ একটি সিআইএল নির্দেশিকা রয়েছে ( .override) যা এটি প্রয়োগ করছে এমন ব্যক্তিগত ইন্টারফেস পদ্ধতির সাথে ব্যক্তিগত পদ্ধতির লিঙ্ক করবে।

[সি #]

class MyClass : MyInterface {
  void MyInterface.Method() {}
}

[CIL]

.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
  .override MyInterface::Method
}

ভিবি.এনইটি তে, আপনি বাস্তবায়নকারী ক্লাসে ইন্টারফেস পদ্ধতির নামও উপনাম করতে পারেন।

[VB.NET]

Public Class MyClass
  Implements MyInterface
  Public Sub AliasedMethod() Implements MyInterface.Method
  End Sub
End Class

[CIL]

.method public newslot virtual final instance void AliasedMethod() cil managed
{
  .override MyInterface::Method
}

এখন, এই অদ্ভুত ঘটনাটি বিবেচনা করুন:

interface MyInterface {
  void Method();
}
class Base {
  public void Method();
}
class Derived : Base, MyInterface { }

যদি Baseএবং Derivedএকই সমাবেশে ঘোষিত হয় তবে Base::Methodসংকলকটি ভার্চুয়াল এবং সিল করে দেবে (সিআইএল), যদিও Baseইন্টারফেসটি কার্যকর করে না।

যদি Baseএবং Derivedবিভিন্ন সমাবেশে থাকে, অ্যাসেম্বলিকে সংকলন করার সময়, সংকলকটি Derivedঅন্য সমাবেশটি পরিবর্তন করবে না, সুতরাং এটিতে কোনও সদস্যকে পরিচয় করিয়ে দেওয়া হবে এটির Derivedজন্য একটি স্পষ্ট বাস্তবায়ন MyInterface::Methodহবে কেবলমাত্র কলটি অর্পণ করবে Base::Method

সুতরাং আপনি দেখতে পাচ্ছেন, প্রতিটি ইন্টারফেস পদ্ধতির প্রয়োগের অবশ্যই পলিমারফিক আচরণকে সমর্থন করা উচিত এবং এটি অবশ্যই সিআইএল-তে ভার্চুয়াল হিসাবে চিহ্নিত করা উচিত, যদিও সংকলকটি এটি করতে হুপের মধ্য দিয়ে যেতে হবে।


73

সিএলআরপি থেকে জ্যাফ্রি রিচারকে উদ্ধৃত করে সিএসএআরপি 3 য় সংস্করণের মাধ্যমে

সিএলআর এর প্রয়োজন হয় যে ইন্টারফেস পদ্ধতিগুলি ভার্চুয়াল হিসাবে চিহ্নিত করা উচিত। আপনি যদি আপনার উত্স কোডটিতে পদ্ধতিটিকে স্পষ্টভাবে ভার্চুয়াল হিসাবে চিহ্নিত না করেন তবে সংকলকটি পদ্ধতিটিকে ভার্চুয়াল হিসাবে চিহ্নিত করেছে এবং সিল করেছে; এটি কোনও উত্পন্ন শ্রেণিকে ইন্টারফেস পদ্ধতির ওভাররাইড থেকে বাধা দেয়। আপনি যদি পদ্ধতিটিকে স্পষ্টভাবে ভার্চুয়াল হিসাবে চিহ্নিত করেন তবে সংকলক পদ্ধতিটিকে ভার্চুয়াল হিসাবে চিহ্নিত করে (এবং এটি অবিরত ছেড়ে দেয়); এটি একটি উত্পন্ন শ্রেণিকে ইন্টারফেস পদ্ধতিতে ওভাররাইড করতে দেয়। যদি কোনও ইন্টারফেস পদ্ধতি সিল করা হয় তবে একটি উত্পন্ন শ্রেণি পদ্ধতিটি ওভাররাইড করতে পারে না। তবে, উত্পন্ন শ্রেণি একই ইন্টারফেসটিকে পুনরায় উত্তরাধিকারী করতে পারে এবং ইন্টারফেসের পদ্ধতিগুলির জন্য নিজস্ব বাস্তবায়ন সরবরাহ করতে পারে।


25
উক্তিটি কোনও ভার্চুয়াল চিহ্নিত করার জন্য কেন একটি ইন্টারফেস পদ্ধতির প্রয়োগ প্রয়োজন say কারণ এটি ইন্টারফেসের প্রকারের সাথে বহুত্বপূর্ণ, তাই ভার্চুয়াল পদ্ধতিটি প্রেরণের অনুমতি দেওয়ার জন্য ভার্চুয়াল টেবিলের একটি স্লট দরকার
জর্দো

1
আমি ইন্টারফেস পদ্ধতিটি স্পষ্টভাবে ভার্চুয়াল হিসাবে চিহ্নিত করার অনুমতি পাচ্ছি না এবং ত্রুটি পেয়েছি "ত্রুটি CS0106: সংশোধক 'ভার্চুয়াল' এই আইটেমটির জন্য বৈধ নয়"। V2.0.50727 (আমার পিসির প্রাচীনতম সংস্করণ) ব্যবহার করে পরীক্ষিত।
ccppjava

3
@ccppjava নীচে জোড়াদোর মন্তব্য থেকে, আপনি ক্লাস সদস্যকে চিহ্নিত করেছেন যা সাবক্লাসগুলিকে ক্লাসটিকে ওভাররাইড করার অনুমতি দেওয়ার জন্য ইন্টারফেস ভার্চুয়াল বাস্তবায়ন করে।
ক্রিস্টোফার স্টিভেনসন

13

হ্যাঁ, রানটাইম সম্পর্কিত যতটা ইন্টারফেস বাস্তবায়ন পদ্ধতি ভার্চুয়াল। এটি একটি বাস্তবায়ন বিশদ, এটি ইন্টারফেসকে কাজ করে। ভার্চুয়াল পদ্ধতিগুলি ক্লাসের ভি-টেবিলের স্লট পায়, প্রতিটি স্লটে ভার্চুয়াল পদ্ধতিগুলির মধ্যে একটিতে পয়েন্টার রয়েছে। একটি ইন্টারফেস প্রকারে কোনও বস্তু কাস্ট করা টেবিলের বিভাগে একটি পয়েন্টার তৈরি করে যা ইন্টারফেস পদ্ধতিগুলি প্রয়োগ করে। ইন্টারফেস রেফারেন্স ব্যবহার করে যে ক্লায়েন্ট কোডটি এখন ইন্টারফেস পয়েন্টার, ইত্যাদি থেকে অফসেট 0-এ প্রথম ইন্টারফেস পদ্ধতি পয়েন্টার দেখায়।

আমার মূল উত্তরে আমি যা কম প্রশংসা করেছি তা হ'ল চূড়ান্ত বৈশিষ্ট্যের তাত্পর্য । এটি কোনও উত্পন্ন শ্রেণিকে ভার্চুয়াল পদ্ধতিতে ওভাররাইড করা থেকে বিরত করে। উদ্ভূত শ্রেণীর অবশ্যই ইন্টারফেসটি পুনরায় প্রয়োগ করতে হবে, বাস্তবায়ন পদ্ধতিগুলি বেস শ্রেণীর পদ্ধতিগুলির ছায়া । যা সি # ভাষার চুক্তি বাস্তবায়নের জন্য যথেষ্ট যা বলে যে বাস্তবায়ন পদ্ধতিটি ভার্চুয়াল নয়।

যদি আপনি উদাহরণ শ্রেণিতে ডিসপোজ () পদ্ধতিটি ভার্চুয়াল হিসাবে ঘোষণা করেন তবে আপনি চূড়ান্ত বৈশিষ্ট্যটি সরিয়ে ফেলতে দেখবেন । এখন কোনও উদ্ভূত শ্রেণিকে এটিকে ওভাররাইড করার অনুমতি দেওয়া হচ্ছে।


4

অন্যান্য সংকলিত কোড পরিবেশে, ইন্টারফেসগুলি vtables হিসাবে প্রয়োগ করা হয় - পদ্ধতি সংস্থাগুলির পয়েন্টারের একটি তালিকা। সাধারণত এমন একটি শ্রেণি যা একাধিক ইন্টারফেস প্রয়োগ করে তার অভ্যন্তরীণ সংকলকটিতে মেটাডেটা তৈরি করা ইন্টারফেস ভিটিবলের একটি তালিকা থাকবে, ইন্টারফেসের জন্য একটি ভেটেবল (যাতে পদ্ধতিটি অর্ডার সংরক্ষণ করা হয়)। এইভাবে সিওএম ইন্টারফেসগুলি সাধারণত কার্যকরভাবে প্রয়োগ করা হয়।

.NET- তে, যদিও ইন্টারফেসগুলি প্রতিটি শ্রেণীর জন্য স্বতন্ত্র vtables হিসাবে প্রয়োগ করা হয় না। ইন্টারফেস পদ্ধতিগুলি বিশ্বব্যাপী ইন্টারফেস পদ্ধতি সারণীর মাধ্যমে সূচী করা হয় যা সমস্ত ইন্টারফেসের একটি অংশ part সুতরাং, কোনও ইন্টারফেস পদ্ধতি প্রয়োগের জন্য সেই পদ্ধতিটির জন্য কোনও পদ্ধতি ভার্চুয়াল ঘোষণা করার প্রয়োজন নেই - গ্লোবাল ইন্টারফেস পদ্ধতি সারণীটি কেবল শ্রেণীর পদ্ধতির কোড ঠিকানাটিতে সরাসরি নির্দেশ করতে পারে।

ইন্টারফেস বাস্তবায়নের জন্য কোনও পদ্ধতি ভার্চুয়াল ঘোষণা করার জন্য অন্য ভাষাগুলিতেও প্রয়োজন হয় না, এমনকি সিএলআরবিহীন প্ল্যাটফর্মগুলিতেও। উইন 32-তে ডেলফি ভাষা এর একটি উদাহরণ।


0

এগুলি ভার্চুয়াল নয় (আমরা সেগুলি কীভাবে বিবেচনা করি তার পরিপ্রেক্ষিতে, যদি অন্তর্নিহিত প্রয়োগের ক্ষেত্রে (সিল করা ভার্চুয়াল) হিসাবে না হয় - অন্য উত্তরগুলি এখানে পড়তে এবং নিজেই কিছু শিখতে ভাল :-)

তারা কিছুতেই ওভাররাইড করে না - ইন্টারফেসে কোনও প্রয়োগ নেই।

সমস্ত ইন্টারফেসটি এমন একটি "চুক্তি" সরবরাহ করে যা শ্রেণিকে মেনে চলতে হয় - একটি প্যাটার্ন, যদি আপনি পছন্দ করেন, যাতে কলাররা জানতে পারে যে কীভাবে তারা সেই নির্দিষ্ট বর্গটি আগে কখনও দেখেনি, এমনকি কীভাবে তাকে কীভাবে কল করতে হবে।

চুক্তি - ভার্চুয়াল বা "নন-ভার্চুয়াল" (সীলমোহরিত ভার্চুয়ালটি যেমন সরে যায়) তখন ইন্টারফেস পদ্ধতিটি যেমনটি হবে ঠিক তেমন প্রয়োগ করা ক্লাসের উপর নির্ভর করে।


এই থ্রেডের প্রত্যেকেই জানেন যে ইন্টারফেসগুলি কী জন্য। প্রশ্ন অত্যন্ত নির্দিষ্ট হয় - উত্পন্ন আইএল হয় ইন্টারফেস পদ্ধতি জন্য ভার্চুয়াল এবং একটি অ-ইন্টারফেস পদ্ধতি জন্য ভার্চুয়াল নয়।
রেক্স এম

5
হ্যাঁ, প্রশ্ন সম্পাদনার পরে কোনও উত্তরটির সমালোচনা করা সত্যিই সহজ, তাই না?
জেসন উইলিয়ামস

0

ইন্টারফেসগুলি ক্লাসের চেয়ে আরও বিমূর্ত ধারণা, যখন আপনি কোনও ক্লাস ঘোষণা করেন যা একটি ইন্টারফেস প্রয়োগ করে, আপনি কেবল "ক্লাসটি ইন্টারফেস থেকে এই বিশেষ পদ্ধতিগুলি থাকা আবশ্যক, এবং কোন স্থানে স্থির , ভার্চুয়াল ব্যাপার না , অ ভার্চুয়াল , ওভাররাইড , যেমন যতক্ষণ না এটির একই আইডি এবং একই ধরণের পরামিতি থাকে।

অন্যান্য ভাষাগুলি যেমন ইন্টারফেস সমর্থন করে যেমন অবজেক্ট পাস্কেল ("ডেল্ফি") এবং অবজেক্টিভ সি (ম্যাক) এর জন্য ইন্টারফেস পদ্ধতিগুলি ভার্চুয়াল নয়, ভার্চুয়াল হিসাবে চিহ্নিত করার প্রয়োজন হয় না।

তবে, আপনি সঠিক হতে পারেন, আমি মনে করি ইন্টারফেসগুলিতে একটি নির্দিষ্ট "ভার্চুয়াল" / "ওভাররাইড" বৈশিষ্ট্য থাকা ভাল ধারণা হতে পারে, যদি আপনি কোনও নির্দিষ্ট ইন্টারফেস প্রয়োগ করে এমন ক্লাসের পদ্ধতিগুলি সীমাবদ্ধ করতে চান । তবে, এর অর্থ উভয় ইন্টারফেসের জন্য একটি "নন ভার্চুয়াল", "ডন্টকারিফর্চুয়ালুয়ালোটনোট" কীওয়ার্ড রয়েছে।

আমি আপনার প্রশ্নটি বুঝতে পেরেছি, কারণ আমি জাভাতেও অনুরূপ কিছু দেখতে পাচ্ছি, যখন কোনও শ্রেণি পদ্ধতিতে ভার্চুয়াল হওয়ার বিষয়টি নিশ্চিত হওয়ার জন্য "@ ভার্চুয়াল" বা "@ ওভাররাইড" ব্যবহার করতে হয়।


@ ওভাররাইড আসলে কোডের আচরণ পরিবর্তন করে না বা ফলস্বরূপ বাইট কোডকে পরিবর্তন করে না। এটি যা করে তা সংকলকটি সিগন্যাল করে যে সাজানো পদ্ধতিটি একটি ওভাররাইড হিসাবে লক্ষ্য করা হচ্ছে, যা সংকলকটি কিছু স্যানিটি চেক করতে দেয়। সি # বিভিন্নভাবে কাজ করে; overrideভাষাতেই এটি প্রথম শ্রেণির কীওয়ার্ড।
রবার্ট হার্ভে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.