Tür uzantıları

Tür uzantıları (genişletmeler olarak da adlandırılan), önceden tanımlanmış bir nesne türüne yeni üye eklemenize izin verilen bir özellik ailesidir. Üç özellik şunlardır:

  • Iç tür uzantıları
  • İsteğe bağlı tür uzantıları
  • Genişletme yöntemleri

Her biri farklı senaryolarda kullanılabilir ve farklı tradeoff'lara sahip olur.

Syntax

// Intrinsic and optional extensions
type typename with
    member self-identifier.member-name =
        body
    ...

// Extension methods
open System.Runtime.CompilerServices

[<Extension>]
type Extensions() =
    [<Extension>]
    static member extension-name (ty: typename, [args]) =
        body
    ...

Iç tür uzantıları

Iç tür uzantısı, kullanıcı tanımlı bir türü genişleten bir tür uzantısıdır.

Iç tür uzantıları, genişlettikleri türle aynı dosyada ve aynı ad alanı veya modülde tanımlanmalıdır. Diğer tüm tanımlar isteğe bağlı tür uzantılarına neden olur.

Iç tür uzantıları bazen işlevselliği tür bildiriminden ayırmanın daha temiz bir yoludur. Aşağıdaki örnekte, iç tür uzantısının nasıl tanımladığınız gösterir:

namespace Example

type Variant =
    | Num of int
    | Str of string
  
module Variant =
    let print v =
        match v with
        | Num n -> printf "Num %d" n
        | Str s -> printf "Str %s" s

// Add a member to Variant as an extension
type Variant with
    member x.Print() = Variant.print x

Tür uzantısı kullanmak, aşağıdakilerin her birini ayırmaya olanak sağlar:

  • Bir türün Variant bildirimi
  • "Şekline" Variant bağlı olarak sınıfı yazdırma işlevi
  • Nesne stiline sahip -notation ile yazdırma işlevine . erişmenin bir yolu

Bu, üzerinde her şeyi üye olarak tanımlamaya Variant alternatiftir. Doğal olarak daha iyi bir yaklaşım değildir, ancak bazı durumlarda işlevselliğin daha temiz bir gösterimi olabilir.

Iç tür uzantıları, artırıldıları türün üyeleri olarak derlenmiş ve tür yansıma tarafından incelendiğinde tür üzerinde görünür.

İsteğe bağlı tür uzantıları

İsteğe bağlı tür uzantısı, genişletiliyor olan türün özgün modülü, ad alanı veya derlemesi dışında görünen bir uzantıdır.

İsteğe bağlı tür uzantıları, kendi tanımlanmamış bir türü genişletmek için kullanışlıdır. Örnek:

module Extensions

type IEnumerable<'T> with
    /// Repeat each element of the sequence n times
    member xs.RepeatElements(n: int) =
        seq {
            for x in xs do
                for _ in 1 .. n -> x
        }

Artık modül, üzerinde çalışmakta olduğu kapsamda açık olduğu sürece üyesi gibi RepeatElements IEnumerable<T> Extensions erişabilirsiniz.

Yansıma tarafından incelendiğinde genişletilmiş türde isteğe bağlı uzantılar görünmez. İsteğe bağlı uzantılar modüllerde olmalı ve yalnızca uzantıyı içeren modül açık olduğunda veya kapsamda değilse kapsamdadır.

İsteğe bağlı uzantı üyeleri, nesne örneğinin ilk parametre olarak örtülü olarak geçir olduğu statik üyelere derlenmiş olur. Ancak, nasıl bildirildiklerini göre örnek üyeleri veya statik üyeler gibi davranırlar.

İsteğe bağlı uzantı üyeleri C# veya diğer kullanıcılar Visual Basic görünmez. Bunlar yalnızca diğer F# kodunda tüketilebilir.

Genel iç ve isteğe bağlı tür uzantıları sınırlaması

Tür değişkeninin kısıtlanmış olduğu genel bir tür üzerinde bir tür uzantısı bildir mümkündür. Gereksinim, uzantı bildiriminin kısıtlaması bildirilen türün kısıtlaması ile eşleşmesidir.

Ancak, kısıtlamalar bildirilen bir tür ile tür uzantısı arasında eşlense bile, bir kısıtlamanın bildirilen türden farklı bir türe göre tür parametresinde farklı bir gereksinime neden olan genişletilmiş üye gövdesi tarafından ertelenmiş olması mümkündür. Örnek:

open System.Collections.Generic

// NOT POSSIBLE AND FAILS TO COMPILE!
//
// The member 'Sum' has a different requirement on 'T than the type IEnumerable<'T>
type IEnumerable<'T> with
    member this.Sum() = Seq.sum this

Bu kodun isteğe bağlı tür uzantısıyla çalışması için bir yol yoktur:

  • Olduğu gibi, Sum üyenin tür uzantısının tanımladığı 'T kısıtlamadan farklı bir kısıtlaması ( static member get_Zero ve ) static member (+) vardır.
  • Tür uzantısını ile aynı kısıtlamaya sahip olacak şekilde değiştirmek Sum artık üzerinde tanımlanan kısıtlamayla eşleşmez. IEnumerable<'T>
  • member this.Sumdeğerinin member inline this.Sum olarak değiştirilmesi, tür kısıtlamalarının eşleşmeyen bir hataya neden olur.

İstenilen, "uzayda kayan" statik yöntemlerdir ve bir türü genişlettikleri gibi sunabilirsiniz. Uzantı yöntemleri bu noktada gerekli hale geldi.

Genişletme yöntemleri

Son olarak, uzantı yöntemleri (bazen "C# stili uzantı üyeleri" olarak adlandırılır), F# içinde bir sınıfta statik üye yöntemi olarak bildirebilirsiniz.

Uzantı yöntemleri, tür değişkenlerini kısıtacak genel bir tür üzerinde uzantılar tanımlamak istediğiniz zaman kullanışlıdır. Örnek:

namespace Extensions

open System.Collections.Generic
open System.Runtime.CompilerServices

[<Extension>]
type IEnumerableExtensions =
    [<Extension>]
    static member inline Sum(xs: IEnumerable<'T>) = Seq.sum xs

Bu kod kullanılırken, açık veya kapsamda olduğu sürece üzerinde tanımlanmış gibi Sum IEnumerable<T> Extensions görünür.

Uzantının kodda kullanılabilir VB.NET için derleme düzeyinde ExtensionAttribute fazladan bir ek gereklidir:

module AssemblyInfo
open System.Runtime.CompilerServices
[<assembly:Extension>]
do ()

Diğer açıklamalar

Tür uzantıları aşağıdaki özniteliklere de sahip:

  • Erişilebilen herhangi bir tür genişletilmiş olabilir.
  • Yalnızca yöntemleri değil, iç ve isteğe bağlı tür uzantıları herhangi bir üye türünü tanımlayabilir. Bu nedenle, örneğin uzantı özellikleri de mümkündür.
  • Sözdiziminde self-identifier belirteci, sıradan üyeler gibi çağrılan türün örneğini temsil eder.
  • Genişletilmiş üyeler statik veya örnek üyeleri olabilir.
  • Tür uzantısında tür değişkenleri, bildirilen türün kısıtlamalarıyla eşleşmeli.

Tür uzantıları için aşağıdaki sınırlamalar da mevcuttur:

  • Tür uzantıları sanal veya soyut yöntemleri desteklemez.
  • Tür uzantıları, geçersiz kılma yöntemlerini genişletme olarak desteklemez.
  • Tür uzantıları Statik Olarak Çözümlenmiş Tür Parametrelerini desteklemez.
  • İsteğe bağlı Tür uzantıları, oluşturucuları genişletme olarak desteklemez.
  • Tür uzantıları, tür kısaltmaları üzerinde tanımlanmalıdır.
  • Tür uzantıları için geçerli değildir byref<'T> (bildirilene rağmen).
  • Tür uzantıları öznitelikler için geçerli değildir (bildirilene rağmen).
  • Aynı adla diğer yöntemleri aşırı yük eden uzantılar tanımlayabilirsiniz, ancak belirsiz bir çağrı varsa F# derleyicisi uzantı olmayan yöntemlere tercih verir.

Son olarak, bir tür için birden çok iç tür uzantısı varsa, tüm üyeler benzersiz olmalıdır. İsteğe bağlı tür uzantıları için, aynı türe sahip farklı tür uzantılarında üyeler aynı adlara sahip olabilir. Belirsizlik hataları yalnızca istemci kodu aynı üye adlarını tanımlayan iki farklı kapsam açtığında oluşur.

Ayrıca bkz.