Öyleyse, bir arabirimi açıkça uygulamak için iyi bir kullanım durumu tam olarak nedir?
Sadece sınıfı kullanan insanların intellisense'deki tüm bu yöntemlere / özelliklere bakmasına gerek kalmaması için mi?
Öyleyse, bir arabirimi açıkça uygulamak için iyi bir kullanım durumu tam olarak nedir?
Sadece sınıfı kullanan insanların intellisense'deki tüm bu yöntemlere / özelliklere bakmasına gerek kalmaması için mi?
Yanıtlar:
Hem aynı yöntemle hem de farklı uygulamalarla iki arabirim uygularsanız, açıkça uygulamanız gerekir.
public interface IDoItFast
{
void Go();
}
public interface IDoItSlow
{
void Go();
}
public class JustDoIt : IDoItFast, IDoItSlow
{
void IDoItFast.Go()
{
}
void IDoItSlow.Go()
{
}
}
Tercih edilmeyen üyeyi gizlemek faydalıdır. Örneğin, her ikisini de uygularsanız IComparable<T>
ve insanlara farklı türdeki nesneleri karşılaştırabileceğiniz izlenimi vermemek IComparable
için IComparable
aşırı yükü gizlemek genellikle daha hoş olur . Benzer şekilde, bazı arabirimler CLS uyumlu değildir IConvertible
, bu nedenle arabirimi açık bir şekilde uygulamazsanız, CLS uyumluluğu gerektiren dillerin son kullanıcıları nesnenizi kullanamaz. (BCL uygulayıcıları ilkellerin IConvertible üyelerini gizlemeseydi bu çok feci olurdu :))
Bir başka ilginç not ise, normalde böyle bir yapının kullanılması, bir arabirimi açıkça uygulayan yapının yalnızca arabirim türüne göre kutulama yaparak çağırabileceği anlamına gelir. Genel kısıtlamaları kullanarak bunun üstesinden gelebilirsiniz:
void SomeMethod<T>(T obj) where T:IConvertible
Bir int verdiğinizde kutuya girmeyecektir.
string
jenerik ilaçlardan önce ortalıktaydı ve bu uygulama revaçtaydı. .Net 2 geldiğinde, genel arayüzünü kırmak istemediler, bu string
yüzden koruma önlemi yerinde olduğu gibi bıraktılar.
Bir arabirimi açıkça uygulamak için bazı ek nedenler:
geriye dönük uyumluluk : ICloneable
Arabirimin değişmesi durumunda, yöntem sınıfı üyelerinin uygulanması yöntem imzalarını değiştirmek zorunda değildir.
temiz kod : Clone
yöntem ICloneable'dan kaldırılırsa bir derleyici hatası olur , ancak yöntemi örtük olarak uygularsanız kullanılmayan 'öksüz' genel yöntemlerle sonuçlanabilirsiniz
Güçlü tipleme : Supercat'ın hikayesini bir örnekle göstermek için, bu benim tercih ettiğim örnek koddur, ICloneable
açıkça uygulamak, Clone()
onu doğrudan bir MyObject
örnek üyesi olarak çağırdığınızda güçlü bir şekilde yazılmasına izin verir :
public class MyObject : ICloneable
{
public MyObject Clone()
{
// my cloning logic;
}
object ICloneable.Clone()
{
return this.Clone();
}
}
interface ICloneable<out T> { T Clone(); T self {get;} }
. ICloneable<T>
T üzerinde kasıtlı olarak hiçbir kısıtlama olmadığına dikkat edin. Bir nesne genellikle yalnızca tabanı olabiliyorsa güvenli bir şekilde klonlanabilirken, bir kişi, güvenli bir şekilde klonlanamayan bir sınıf nesnesini klonlayabilen bir temel sınıftan türetmek isteyebilir. Buna izin vermek için, devralınabilir sınıfların genel bir klon yöntemini açığa çıkarmasını önermiyorum. Bunun yerine, bir protected
klonlama yöntemine sahip devralınabilir sınıflara ve bunlardan türetilen ve genel klonlamayı ortaya çıkaran mühürlenmiş sınıflara sahip olun.
Bir başka yararlı teknik, bir fonksiyonun bir yöntemin genel uygulamasının bir arayüzde belirtilenden daha spesifik bir değer döndürmesini sağlamaktır.
Örneğin, bir nesne uygulayabilir ICloneable
, ancak yine de genel olarak görülebilen Clone
yöntemi kendi türünü döndürür.
Benzer şekilde, bir, bir döndüren bir yönteme sahip IAutomobileFactory
olabilir , ancak uygulayan a , kendi yönteminin dönüşüne ( a) sahip olabilir (türetilen ). A tarafından döndürülen bir nesnede kullanabileceğine özgü özelliklere sahip olduğunu bilen kod, yalnızca bir tür olduğunu bilen kod , bir .Manufacture
Automobile
FordExplorerFactory
IAutomobileFactory
Manufacture
FordExplorer
Automobile
FordExplorerFactory
FordExplorer
FordExplorerFactory
IAutomobileFactory
Automobile
Aynı üye adı ve imzasına sahip iki arabiriminiz olduğunda, ancak nasıl kullanıldığına bağlı olarak davranışını değiştirmek istediğinizde de yararlıdır. (Böyle bir kod yazmayı önermiyorum):
interface Cat
{
string Name {get;}
}
interface Dog
{
string Name{get;}
}
public class Animal : Cat, Dog
{
string Cat.Name
{
get
{
return "Cat";
}
}
string Dog.Name
{
get
{
return "Dog";
}
}
}
static void Main(string[] args)
{
Animal animal = new Animal();
Cat cat = animal; //Note the use of the same instance of Animal. All we are doing is picking which interface implementation we want to use.
Dog dog = animal;
Console.WriteLine(cat.Name); //Prints Cat
Console.WriteLine(dog.Name); //Prints Dog
}
public class Animal : Cat, Dog
Bir arabirimi açıkça uygulamak için genel arabirimi daha temiz tutabilir, yani File
sınıfınız IDisposable
açıkça uygulayabilir ve Close()
bir tüketiciye göre daha anlamlı olabilecek bir genel yöntem sağlayabilir Dispose(
).
F # yalnızca açık arabirim uygulaması sunar, bu nedenle işlevine erişmek için her zaman belirli arabirime çevirmeniz gerekir, bu da arabirimin çok açık (amaçsız) kullanımını sağlar.
Dispose
asla temizlik gerektirmeyecek olanlardır); daha iyi bir örnek, değişmez bir koleksiyonun uygulaması gibi bir şey olabilir IList<T>.Add
.
Açık uygulamanın bir başka nedeni de sürdürülebilirliktir .
Bir sınıf "meşgul" olduğunda - evet öyle, hepimiz diğer ekip üyelerinin kodunu yeniden düzenleme lüksüne sahip değiliz - o zaman açık bir uygulamaya sahip olmak, bir arayüz sözleşmesini yerine getirmek için bir yöntemin orada olduğunu açıkça ortaya koyuyor.
Böylece kodun "okunabilirliğini" geliştirir.
#region
uygun bir başlık dizesiyle bunun için olan şey budur. Ve yöntem hakkında bir yorum.
System.Collections.Immutable
Yazarların, yeni türleri için hiçbir anlam taşımayan arayüz parçalarını sıyırırken koleksiyon türleri için tanıdık bir API'yi korumak için tekniği kullanmayı seçtikleri farklı bir örnekle verilmiştir .
Somut olarak, ImmutableList<T>
uygular IList<T>
, böylece ve ICollection<T>
( sırayla izin ImmutableList<T>
henüz eski kodu ile daha kolay kullanılmak üzere) void ICollection<T>.Add(T item)
bir anlamsızdır ImmutableList<T>
, mevcut listesini değiştirmek gerekir değişmez bir listeye bir öğe ekleyerek tarihi: ImmutableList<T>
ayrıca türeten gelen IImmutableList<T>
kimin IImmutableList<T> Add(T item)
için kullanılabilir değişmez listeler.
Dolayısıyla, söz konusu Add
uygulamalarda ImmutableList<T>
aşağıdaki gibi sonuçlanır:
public ImmutableList<T> Add(T item)
{
// Create a new list with the added item
}
IImmutableList<T> IImmutableList<T>.Add(T value) => this.Add(value);
void ICollection<T>.Add(T item) => throw new NotSupportedException();
int IList.Add(object value) => throw new NotSupportedException();
Açıkça tanımlanmış arabirimler olması durumunda, tüm yöntemler otomatik olarak özeldir, bunlara erişim değiştiriciyi genel olarak veremezsiniz. varsayalım:
interface Iphone{
void Money();
}
interface Ipen{
void Price();
}
class Demo : Iphone, Ipen{
void Iphone.Money(){ //it is private you can't give public
Console.WriteLine("You have no money");
}
void Ipen.Price(){ //it is private you can't give public
Console.WriteLine("You have to paid 3$");
}
}
// So you have to cast to call the method
class Program
{
static void Main(string[] args)
{
Demo d = new Demo();
Iphone i1 = (Iphone)d;
i1.Money();
((Ipen)i1).Price();
Console.ReadKey();
}
}
// You can't call methods by direct class object
Açık Arabirimi bu şekilde oluşturabiliriz: Eğer 2 arabirimimiz varsa ve her iki arabirim de aynı yönteme sahipse ve tek bir sınıf bu 2 arabirimi miras alır, bu nedenle bir arabirim yöntemini çağırdığımızda derleyici hangi yöntemin çağrılacağını karıştırır, böylece yapabiliriz Explicit Interface kullanarak bu sorunu yönetin. İşte aşağıda verdiğim bir örnek.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace oops3
{
interface I5
{
void getdata();
}
interface I6
{
void getdata();
}
class MyClass:I5,I6
{
void I5.getdata()
{
Console.WriteLine("I5 getdata called");
}
void I6.getdata()
{
Console.WriteLine("I6 getdata called");
}
static void Main(string[] args)
{
MyClass obj = new MyClass();
((I5)obj).getdata();
Console.ReadLine();
}
}
}