Genişletme Methodları (Extension Methods)

Genişletme metodları, mevcut kütüphanelere yeni işlevsellik eklemenizi sağlar. Bu metodları, bir IDE'de kod tamamlama özelliğini kullanırken, normal metodlarla birlikte önerilen genişletme metodları da görebilirsiniz.

Başkalarının veya yaygın olarak kullanılan bir kütüphaneyi uyguladığınızda, Kütüphaneyi değiştirmek genellikle pratik veya mümkün olmayabilir. Ancak yine de işlevsellik eklemek isteyebilirsiniz.

Örneğin, bir dizeyi bir tamsayıya çözümleyen aşağıdaki kodu düşünün:

int.parse('42');

Bu işlevselliğin String üzerinde olmasını istiyorsanız, şu şekilde kısaltabilir ve araçlarla daha kolay kullanabilirsiniz:

'42'.parseInt();

Bu kodu etkinleştirmek için, String sınıfına bir genişletme içeren bir kütüphaneyi içe aktarabilirsiniz:

import 'string_apis.dart';
// ···
print('42'.parseInt()); // Genişletme metodunu kullan.

Genişletmeler sadece metodları değil, aynı zamanda diğer üyeleri de (getter, setter ve operatörler gibi) tanımlayabilir. Ayrıca, genişletmelerin isimleri olabilir ve bu, bir API çakışması durumunda yardımcı olabilir. İşte, bir genişletme metodunu uygulayan (NumberParsing adlı) bir genişletmeyi içeren string_apis.dart dosyasını nasıl oluşturabileceğiniz:

string_apis.dart

extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }
  // ···
}

Sonraki bölümde genişletme metodlarını nasıl kullanacağınızı, ardından genişletme metodlarını nasıl uygulayacağınızı açıklıyoruz.

Genişletme Metodlarını Kullanma (Using Extension Methods)

Tıpkı diğer Dart kodları gibi, genişletme metodları da kütüphaneler içindedir. Genişletme metodunu kullanmanın yolu, ilgili kütüphaneyi içe aktarmaktır ve bunu sıradan bir metod gibi kullanmaktır:

// String üzerinde bir genişletme içeren kütüphaneyi içe aktar.
import 'string_apis.dart';
// ···
print('42'.padLeft(5)); // String metodunu kullan.
print('42'.parseInt()); // Genişletme metodunu kullan.

Genellikle genişletme metodlarını kullanmak için bilmeniz gereken tek şey budur. Kodunuzu yazarken genişletme metodlarının statik tiplere (dinamik değil) nasıl bağlı olduğunu ve kütüphane çakışmalarını nasıl çözeceğinizi de bilmek isteyebilirsiniz.

Statik Tipler ve Dinamik (Static Types and Dynamic)

Genişletme metodlarını dinamik türdeki değişkenler üzerinde çağıramazsınız. Örneğin, aşağıdaki kod bir çalışma zamanı hatasına neden olur:

dynamic d = '2';
print(d.parseInt()); // Çalışma zamanı hatası: NoSuchMethodError

Genişletme metodları, Dart'ın tür çıkarımı ile çalışır. Aşağıdaki kod sorunsuz çalışır çünkü değişken v'nin türü String olarak çıkarılır:

var v = '2';
print(v.parseInt()); // Çıktı: 2

Dinamik türün çalışmamasının nedeni, genişletme metodlarının alıcının statik türüne karşı çözümlendiğidir. Genişletme metodları statik olarak çözümlendiği için, bunlar statik bir fonksiyonu çağırmak kadar hızlıdır.

Daha fazla bilgi için statik tipler ve dinamik konusuna bakmak için Dart tür sistemine göz atın.

API Çakışmaları (API Conflicts)

Eğer bir genişletme üyesi bir arayüzle veya başka bir genişletme üyesiyle çakışıyorsa, birkaç seçeneğiniz vardır.

Bir seçenek, çakışan genişletmeyi nasıl içe aktardığınızı değiştirmektir, show veya hide kullanarak maruz bırakılan API'yi sınırlayabilirsiniz:

// String üzerinde parseInt() genişletme metodunu tanımlar.
import 'string_apis.dart';

// parseInt() metodunu aynı şekilde tanımlar, ancak NumberParsing2'yi gizleyerek
// bu genişletme metodunu gizler.
import 'string_apis_2.dart' hide NumberParsing2;

// ···
// 'string_apis.dart' içinde tanımlanan parseInt()'i kullanır.
print('42'.parseInt());

Başka bir seçenek, genişletmeyi açıkça uygulamaktır; bu, genişletmenin bir sarma sınıfı gibi göründüğü kodu içerir:

dartCopy code// Hem 'string_apis.dart' hem de 'string_apis_2.dart'
// String üzerinde parseInt() içeren genişletmeleri tanımlar.
import 'string_apis.dart'; // NumberParsing genişletmesini içerir.
import 'string_apis_2.dart'; // NumberParsing2 genişletmesini içerir.

// ···
// print('42'.parseInt()); // Çalışmaz.
print(NumberParsing('42').parseInt());
print(NumberParsing2('42').parseInt());

Eğer her iki genişletme de aynı isme sahipse, o zaman bir ön ek kullanarak içe aktarmak gerekebilir:

dartCopy code// Her iki kütüphane de NumberParsing isimli genişletmeleri tanımlar
// ve parseInt() genişletme metodunu içerir. 'string_apis_3.dart'
// içindeki NumberParsing genişletmesi ayrıca parseNum() metodunu da tanımlar.
import 'string_apis.dart';
import 'string_apis_3.dart' as rad;

// ···
// print('42'.parseInt()); // Çalışmaz.

// 'string_apis.dart' içindeki ParseNumbers genişletmesini kullanın.
print(NumberParsing('42').parseInt());

// 'string_apis_3.dart' içindeki ParseNumbers genişletmesini kullanın.
print(rad.NumberParsing('42').parseInt());

// 'string_apis_3.dart' sadece parseNum() metodunu içerir.
print('42'.parseNum());

Bu örnek gösteriyor ki, bir ön ek kullanarak içe aktarırsanız, genişletme metodlarını açıkça çağırmadan da genişletme metodlarını örtük olarak çağırabilirsiniz. Sadece bir genişletmeyi açıkça çağırmak için bir isim çakışmasını önlemek için ön ek kullanmanız gerekir.

Genişletme Metodlarını Uygulama (Implementing Extension Methods)

Bir genişletme oluşturmak için aşağıdaki sözdizimini kullanın:

extension <genişletme adı>? on <tip> {
  (<üye tanımı>)*
}

Örneğin, String sınıfına bir genişletme nasıl uygulayabileceğinizi aşağıda görebilirsiniz:

string_apis.dart

extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }

  double parseDouble() {
    return double.parse(this);
  }
}

Bir genişletmenin üyeleri metodlar, getter'lar, setter'lar veya operatörler olabilir. Genişletmeler ayrıca statik alanlara ve statik yardımcı metodlara da sahip olabilir. Genişletme dışında statik üyelere erişmek için, bunları sınıf değişkenleri ve metodları gibi adlarıyla çağırın.

İsimsiz Genişletmeler (Unnamed Extension)

Bir genişletme bildirirken, ismi atlayabilirsiniz. İsimsiz genişletmeler, yalnızca tanımlandıkları kütüphanede görünür. İsimleri olmadığı için, açıkça uygulanamazlar ve API çakışmalarını çözemezler.

extension on String {
  bool get isBlank => trim().isEmpty;
}

Not

İsimsiz genişletmenin statik üyelerini, yalnızca genişletme bildirisi içinde kullanabilirsiniz.

Jenerik Genişletmeleri Uygulama (Implementing Generic Extensions)

Genişletmeler, jenerik tür parametrelerine sahip olabilir. Örneğin, yerleşik List<T> türünü bir getter, bir operatör ve bir metod ile genişleten bir kod parçası aşağıdaki gibidir:

extension MyFancyList<T> on List<T> {
  int get doubleLength => length * 2;
  List<T> operator -() => reversed.toList();
  List<List<T>> split(int at) => [sublist(0, at), sublist(at)];
}

Tür T, çağrılan metodların üzerinde çalıştığı listenin statik türüne bağlı olarak bağlanır.

Last updated