Aracılığıyla paylaş


Öğretici: bir tür sağlayıcısı (F#) oluşturma

F# 3.0 içindeki tür sağlayıcısı mekanizması bilgi zengin programlama desteğinin önemli bir bölümüdür. Bu adım adım kılavuz temel kavramları açıklamak için birkaç basit tür sağlayıcılarının geliştirilmesinde sizi adım adım yönlendirerek nasıl kendi tür sağlayıcılarınızı oluşturabileceğinizi açıklar. F# içinde tür sağlayıcısı mekanizması hakkında daha fazla bilgi için, bkz: Sağlayıcı türü.

F# 3.0 Internet ve kurumsal veri hizmetlerinde yaygın olarak kullanılan birkaç yerleşik tür sağlayıcısı içerir. Bu tür sağlayıcıları SQL ilişkisel veritabanlarına ve ağ-tabanlı OData ve WSDL hizmetlerine basit ve devamlı erişim sağlar. Bu sağlayıcılar aynı zamanda bu veri kaynaklarına karşılık F# LINQ sorguları kullanımını destekler.

Gerekten yerlerde, özel tür sağlayıcıları oluşturabilir, ya da başkalarının oluşturduğu tür sağlayıcılarına başvurabilirsiniz. Örneğin, kuruluşunuz her biri kendi kararlı veri şemasına sahip çok ve artan sayıda adlandırılmış veri kümeleri sağlayan bir veri hizmetine sahip olabilir. Şemaları okuyan ve geçerli veri kümelerini programcıya türü kesin belirlenmiş bir biçimde sunan bir tür sağlayıcısı oluşturabilirsiniz.

Başlamadan Önce

Tür sağlayıcısı mekanizması öncelikle F# programlama deneyimine karalı veri ve hizmet bilgi uzayları eklemek için tasarlanmıştır.

Bu mekanizma program mantığına göre program yürütülmesi sırasında şeması değişen bilgi uzayları eklemek için tasarlanmamıştır. Ayrıca, o konuda bazı geçerli kullanımlar içerse bile mekanizma iç-dil meta-programlama için tasarlanmamıştır. Bu mekanizmayı yalnızca gerekli olduğunda ve bir tür sağlayıcısının geliştirilmesinin çok yüksek bir değer sağladığı durumlarda kullanmalısınız.

Kullanılabilir bir şema olmadığı zaman bir tür sağlayıcısı yazmaktan kaçınmalısınız. Aynı şekilde, basit bir (hatta varolan) .NET kitaplığının yeterli olacağı durumlarda bir tür sağlayıcısı yazmaktan kaçınmalısınız.

Başlamadan önce, aşağıdaki soruları sorabilirsiniz:

  • Bilgi kaynağınız için bir şemanız var mı? Eğer varsa, F# ve .NET tür sistemi içine eşleştirilmesi nedir?

  • Uygulamanız için varolan bir (dinamik türlü) API'yı başlangıç noktası olarak kullanabilir misiniz?

  • Sizin ve kuruluşunuzun tür sağlayıcısını yazmaya değecek kadar çok kullanım alanı var mı? Normal bir .NET kitaplığı ihtiyaçlarınızı karşılar mı?

  • Şemanız ne kadar değişecek?

  • Kodlama sırasında değişecek mi?

  • Kodlama oturumları arasında değişecek mi?

  • Program yürütülmesi sırasında değişecek mi?

Tür sağlayıcıları şemanın çalışma zamanında ve derlenen kodun yaşam süresi boyunca kararlı olduğu durumlar için uygundur.

Basit Bir Tür Sağlayıcısı

Bu örnek F# 3.0 Örnek Paketi içindeki SampleProviders\Providers klasörü içindeki Samples.HelloWorldTypeProvider örneğidir. Sağlayıcı 100 silinmiş tür içeren bir "tür uzayı" sağlar, ve aşağıdaki kod bunu F# imza sözdizimi kullanarak ve Type1 dışındaki detayları atlayarak gösterir. Silinmiş türler hakkında daha fazla bilgi için, bu konuda daha sonra anlatılan Silinmiş Sağlanmış Türler Hakkında Detaylar bakınız.

namespace Samples.HelloWorldTypeProvider

    type Type1 =
        /// This is a static property.
        static member StaticProperty : string

        /// This constructor takes no arguments.
        new : unit -> Type1

        /// This constructor takes one argument.
        new : data:string -> Type1

        /// This is an instance property.
        member InstanceProperty : int

        /// This is an instance method.
        member InstanceMethod : x:int -> char

        /// This is an instance property.
        nested type NestedType = 
            /// This is StaticProperty1 on NestedType.
            static member StaticProperty1 : string
            …
            /// This is StaticProperty100 on NestedType.
            static member StaticProperty100 : string

    type Type2 =
        …
    …

    type Type100 =
        …

Sağlanan tür ve üye kümesinin statik olarak bilindiğine dikkat edin. Bu örnek sağlayıcıların bir şemaya bağlı olan türleri sağlama yeteneğini kullanmaz. Tür sağlayıcısının uygulaması aşağıdaki kodda ana hatlarıyla gösterilmiştir, ve detayları bu konunun sonraki bölümlerinde anlatılacaktır.

Uyarı

Bu kod ve çevrimiçi örnekler arasında bazı küçük isimlendirme farklılıkları olabilir.

namespace Samples.FSharp.HelloWorldTypeProvider

open System
open System.Reflection
open Samples.FSharp.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
open Microsoft.FSharp.Quotations

// This type defines the type provider. When compiled to a DLL, it can be added
// as a reference to an F# command-line compilation, script, or project.
[<TypeProvider>]
type SampleTypeProvider(config: TypeProviderConfig) as this = 

    // Inheriting from this type provides implementations of ITypeProvider 
    // in terms of the provided types below.
    inherit TypeProviderForNamespaces()

    let namespaceName = "Samples.HelloWorldTypeProvider"
    let thisAssembly = Assembly.GetExecutingAssembly()

    // Make one provided type, called TypeN.
    let makeOneProvidedType (n:int) = 
        …
    // Now generate 100 types
    let types = [ for i in 1 .. 100 -> makeOneProvidedType i ] 

    // And add them to the namespace
    do this.AddNamespace(namespaceName, types)

[<assembly:TypeProviderAssembly>] 
do()

Bu sağlayıcıyı kullanmak için, ayrı bir Visual Studio 2012 örneği açın, bir F# betiği oluşturun, ve ardından aşağıdaki kodun gösterdiği gibi #r kullanarak betiğinizden sağlayıcıya bir başvuru ekleyin:

#r @".\bin\Debug\Samples.HelloWorldTypeProvider.dll"

let obj1 = Samples.HelloWorldTypeProvider.Type1("some data")

let obj2 = Samples.HelloWorldTypeProvider.Type1("some other data")

obj1.InstanceProperty
obj2.InstanceProperty

[ for index in 0 .. obj1.InstanceProperty-1 -> obj1.InstanceMethod(index) ]
[ for index in 0 .. obj2.InstanceProperty-1 -> obj2.InstanceMethod(index) ]

let data1 = Samples.HelloWorldTypeProvider.Type1.NestedType.StaticProperty35

Ardından Samples.HelloWorldTypeProvider ad alanı altında tür sağlayıcısının ürettiği türlere bakın.

Sağlayıcıyı yeniden derlemeden önce, sağlayıcı DLLsini kullanan tüm Visual Studio ve F# Interactive örneklerini kapattığınızdan emin olun. Aksi halde, çıktı DLL kilitli olduğu için bir derleme hatası gerçekleşir.

Bu sağlayıcıyı print ifadeleri kullanarak hata ayıklamak için, sağlayıcıda bir hatayı açığa çıkaran bir betik yazın, ve aşağıdaki kodu kullanın:

fsc.exe -r:bin\Debug\HelloWorldTypeProvider.dll script.fsx

Bu sağlayıcıyı Visual Studio kullanarak hata ayıklamak için, yönetimsel kimlikle Visual Studio komut istemini açın ve aşağıdaki komutu çalıştırın:

devenv.exe /debugexe fsc.exe -r:bin\Debug\HelloWorldTypeProvider.dll script.fsx

Alternatif olarak, Visual Studio'yu açın, Debug menüsünü açın, Debug/Attach to process... seçin, ve betiğinizi düzenlediğiniz diğer devenv işlemini ekleyin. Bu yöntemi kullanarak, ikinci örnek içine etkileşimli olarak ifadeler yazarak (tam IntelliSense ve diğer özellikler ile) tür sağlayıcısındaki belirli mantığı daha kolay hedef alabilirsiniz.

Yalnızca Kendi Kodum hata ayıklamayı devre dışı bırakarak üretilen koddaki hataları daha iyi tanımlayabilirsiniz. Bu özelliğin nasıl etkinleştirilebileceği ya da devre dışı bırakılabileceği ile ilgili bilgi için, bkz: Nasıl yapılır: Yalnızca Benim Kodum'a Dahil Olun Ayrıca, ilk fırsat özel durum yakalamayı ayarlamak için Debug menüsünü açıp Exceptions seçebilir, ya da Exceptions iletişim kutusunu açmak için Ctrl+Alt+E tuşlarını seçebilirsiniz. O iletişim kutusu içinde, Common Language Runtime Exceptions altında, Thrown onay kutusunu seçin.

Hh361034.collapse_all(tr-tr,VS.110).gifTür Sağlayıcısının Uygulanması

Bu bölüm tür sağlayıcısı uygulamasının ana bölümlerinde size adım adım yol gösterir. Öncelikle, özel tür sağlayıcısının kendi türünü tanımlayın:

[<TypeProvider>]
type SampleTypeProvider(config: TypeProviderConfig) as this =

Bu tür genel olmalıdır, ve ayrı bir F# projesi türü içeren bir derlemeye başvurduğunda derleyicinin tür sağlayıcısını tanıması için TypeProvider ile işaretlemeniz gerekir. config parametresi isteğe bağlıdır, ve eğer mevcutsa, F# derleyicisinin oluşturduğu tür sağlayıcısı için bağlamsal yapılandırma bilgisi içerir.

Sonra, ITypeProvider arabirimini uygularsınız. Bu durumda, ProvidedTypes APIsindeki TypeProviderForNamespaces türünü bir temel tür olarak kullanırsınız. Bu yardımcı tür sınırlı bir istekli olarak sağlanan ad alanları koleksiyonu sağlar, ve her biri doğrudan sınırlı sayıda sabit, istekli olarak sağlanan türler içerir. Bu bağlamda, sağlayıcı gerekmeseler ya da kullanılmasalar bile istekli olarak türler üretir.

inherit TypeProviderForNamespaces()

Sonra, sağlanan türler için ad alanını belirleyen yerel özel değerler tanımlayın, ve tür sağlayıcısı derlemesinin kendisini bulun. Bu derleme daha sonra sağlanan silinmiş türlerin mantıksal üst türü olarak kullanılır.

let namespaceName = "Samples.HelloWorldTypeProvider"
let thisAssembly = Assembly.GetExecutingAssembly()

Sonra, her Type1...Type100 türünü sağlayan bir işlev oluşturun. Bu işlev bu konunun ilerisinde daha ayrıntılı olarak açıklanmıştır.

let makeOneProvidedType (n:int) = …

Sonra, 100 sağlanan türü üretin:

let types = [ for i in 1 .. 100 -> makeOneProvidedType i ]

Sonra, türleri bir sağlanan ad alanı olarak ekleyin:

do this.AddNamespace(namespaceName, types)

Son olarak, bir tür sağlayıcısı DLLsi oluşturduğunuzu ifade eden bir derleme özniteliği ekleyin:

[<assembly:TypeProviderAssembly>] 
do()

Hh361034.collapse_all(tr-tr,VS.110).gifBir Tür ve Üyelerini Sağlama

makeOneProvidedType işlevi türlerden birinin sağlanmasının gerçek işini yapar.

let makeOneProvidedType (n:int) = 
        …

Bu adım bu işlevin uygulamasını açıklar. İlk olarak, sağlanan türü oluşturun (örneğin, n = 1 iken Type1 ya da n = 57 iken Type57).

    // This is the provided type. It is an erased provided type and, in compiled code, 
    // will appear as type 'obj'.
    let t = ProvidedTypeDefinition(thisAssembly,namespaceName,
                                       "Type" + string n,
                                       baseType = Some typeof<obj>)



Aşağıdaki noktalara dikkat etmelisiniz:

  • Bu sağlanan tür silinmiştir. Temel türü obj olarak belirttiğiniz için, örnekler derlenmiş kodda obj türü değerler olarak görünür.

  • Bir iç içe olmayan tür belirttiğinizde, derlemeyi ve ad alanını belirtmeniz gerekir. Silinmiş türler için, derleme tür sağlayıcı derlemesinin kendisi olmalıdır.

Sonra, türe XML belgelemesini ekleyin. Bu belgeleme gecikmelidir, yani, eğer ana bilgisayardaki derleyici ihtiyaç duyuyorsa istek anında hesaplanır.

t.AddXmlDocDelayed (fun () -> sprintf "This provided type %s" ("Type" + string n))

Sonra türe bir sağlanmış statik özellik eklersiniz:

let staticProp = ProvidedProperty(propertyName = "StaticProperty", 
                                  propertyType = typeof<string>, 
                                  IsStatic=true,
                                  GetterCode= (fun args -> <@@ "Hello!" @@>))

Bu özelliği almak her zaman "Hello!" dizesine değerlendirilir. Özellik için GetterCode ana derleyicinin özelliği almak için ürettiği kodu temsil eden bir F# alıntısı kullanır. Alıntılar hakkında daha fazla bilgi için, bkz: Kod Alıntıları (F#).

Özelliğe XML belgelemesi ekleyin.

staticProp.AddXmlDocDelayed(fun () -> "This is a static property")

Şimdi sağlanan özelliği sağlanan türe ekleyin. Bir sağlanan üyeyi bir ve yalnızca bir türe eklemelisiniz. Aksi halde, üye asla erişilemez.

t.AddMember staticProp

Şimdi hiçbir parametre almayan bir sağlanan oluşturucu oluşturun.

let ctor = ProvidedConstructor(parameters = [ ], 
                               InvokeCode= (fun args -> <@@ "The object data" :> obj @@>))

Oluşturucu için InvokeCode ana derleyicinin oluşturucuyu çağırdığında ürettiği kodu temsil eden bir F# alıntısı döndürür. Örneğin, aşağıdaki oluşturucuyu kullanabilirsiniz:

new Type10()

Sağlanan türün bir örneği altında "The object data" verisi ile oluşturulacaktır. Alıntılanan kod bir obj dönüşümü içerir çünkü tür bu sağlanan türün silintisidir (sağlanan türü bildirdiğinizde belirttiğiniz şekilde).

Oluşturucuya XML belgelemesi ekleyin, ve sağlanan oluşturucuyu sağlanan türe ekleyin:

ctor.AddXmlDocDelayed(fun () -> "This is a constructor")

t.AddMember ctor

Bir parametre alan ikinci bir sağlanan oluşturucu oluşturun:

let ctor2 = 
    ProvidedConstructor(parameters = [ ProvidedParameter("data",typeof<string>) ], 
                        InvokeCode= (fun args -> <@@ (%%(args.[0]) : string) :> obj @@>))

Oluşturucu için InvokeCode yine ana derleyicinin yöntemi bir çağrı için ürettiği kodu temsil eden bir F# alıntısı döndürür. Örneğin, aşağıdaki oluşturucuyu kullanabilirsiniz:

     new Type10("ten")

Sağlanan türün altında "ten" verisi olan bir örneği oluşturulur. InvokeCode işlevinin bir alıntı döndürdüğünü farketmiş olabilirsiniz. Bu işlevin girişi bir ifadeler listesidir, her oluşturucu parametresi için bir tane. Bu durumda, tek parametre değerini temsil eden bir ifade args.[0] içinde mevcuttur. Oluşturucuya bir çağrı için kod dönüş değerini silinen türe obj zorlar. Türe ikinci sağlanan oluşturucuyu ekledikten sonra, bir sağlanan örnek özelliği oluşturursunuz:

let instanceProp = 
    ProvidedProperty(propertyName = "InstanceProperty", 
                     propertyType = typeof<int>, 
                     GetterCode= (fun args -> 
                                       <@@ ((%%(args.[0]) : obj) :?> string).Length @@>))
instanceProp.AddXmlDocDelayed(fun () -> "This is an instance property")
t.AddMember instanceProp

Bu özelliği almak temsil edilen nesne olan dizenin uzunluğunu döndürür. GetterCode özelliği ana derleyicinin özelliği almak için ürettiği kodu belirten bir F# alıntısı döndürür. InvokeCode gibi, GetterCode işlevi bir alıntı döndürür. Ana derleyici bu işlevi bir bağımsız değişken listesi ile çağırır. Bu durumda, bağımsız değişkenler args.[0] kullanarak erişebileceğiniz alıcının çağırıldığı örneği temsil eden tek ifadeyi içerir. GetterCode uygulaması ardından silinmiş türde obj sonuç alıntısını bağlar, ve derleyicinin türleri denetleme mekanizmasına uymak için bir çevirim kullanılarak nesne bir dize olarak gösterilir. Sonraki makeOneProvidedType bölümü bir parametre ile bir örnek yöntemi sağlar.

let instanceMeth = 
    ProvidedMethod(methodName = "InstanceMethod", 
                   parameters = [ProvidedParameter("x",typeof<int>)], 
                   returnType = typeof<char>, 
                   InvokeCode = (fun args -> 
                       <@@ ((%%(args.[0]) : obj) :?> string).Chars(%%(args.[1]) : int) @@>))

instanceMeth.AddXmlDocDelayed(fun () -> "This is an instance method")
// Add the instance method to the type.
t.AddMember instanceMeth 

Son olarak, 100 iç içe özellik içerek bir iç içe tür oluşturun. Bu iç içe tür ve özelliklerinin oluşumu gecikmelidir, yani, istek anında hesaplanır.

t.AddMembersDelayed(fun () -> 
    let nestedType = ProvidedTypeDefinition("NestedType",
                                            Some typeof<obj>

)

    nestedType.AddMembersDelayed (fun () -> 
        let staticPropsInNestedType = 
            [ for i in 1 .. 100 do
                 let valueOfTheProperty = "I am string "  + string i

                 let p = ProvidedProperty(propertyName = "StaticProperty" + string i, 
                                          propertyType = typeof<string>, 
                                          IsStatic=true,
                                          GetterCode= (fun args -> <@@ valueOfTheProperty @@>))

                 p.AddXmlDocDelayed(fun () -> 
                     sprintf "This is StaticProperty%d on NestedType" i)

                 yield p ]
        staticPropsInNestedType)

    [nestedType])

// The result of makeOneProvidedType is the type.
t

Hh361034.collapse_all(tr-tr,VS.110).gifSilinmiş Sağlanan Türler hakkında Ayrıntılar

Bu bölümdeki örnek yalnızca silinmiş sağlanan türler sağlar, ve aşağıdaki durumlarda kullanışlıdır:

  • Yalnızca veri ve yöntemler içeren bir bilgi uzayına bir sağlayıcı yazarken.

  • Bilgi uzayının pratik kullanımı için doğru çalışma zamanı tür semantiklerinin kritik olmadığı zaman bir sağlayıcı yazarken.

  • Bilgi uzayı için gerçek .NET türleri üretmenin teknik olarak uygulanabilir olamayacağı kadar büyük ve birbirine bağlı bir bilgi uzayı için bir sağlayıcı yazarken.

Bu örnekte, her sağlanan tür obj türüne silinir, ve türün her kullanımı derlenmiş kodda obj türü olarak görünür. Aslında, bu örneklerdeki alttaki nesneler dizelerdir, ama tür .NET derlenmiş kodda Object olarak görünür. Tür silintisinin tüm kullanımları gibi, silinmiş türleri yıkmak için açıkça kutulama, geri kutulama ve çevirim kullanabilirsiniz. Bu durumda, nesne kullanıldığında geçersiz bir çevirim özel durumu ortaya çıkabilir. Bir sağlayıcı çalışma zamanı yanlış temsillere karşı korunmasına yardımcı olmak için kendi özel temsil türünü tanımlayabilir. F#'ın kendisi içinde silinmiş türler tanımlayamazsınız. Yalnızca sağlanan türler silinebilir. Tür sağlayıcınız için silinmiş türler kullanmanın ya da silinmiş türler sağlayan bir sağlayıcı kullanmanın sonuçlarını, hem pratik hem de semantik olarak anlamalısınız. Bir silinmiş türün gerçek .NET türü yoktur. Bu nedenle, tür üzerinde doğru bir yansıma yapamazsınız, ve eğer çalışma zamanı çevirimleri ve aynı çalışma zamanı tür semantiklerine dayanan diğer teknikleri kullanırsanız silinmiş türleri yıkabilirsiniz. Silinmiş türlerin yıkımı çalışma zamanında sıklıkla tür çevirim özel durumlarına neden olur.

Hh361034.collapse_all(tr-tr,VS.110).gifSilinmiş Sağlanan Türler için Temsiller Seçme

Silinmiş sağlanan türlerin bazı kullanımları için, temsil gerekli değildir. Örneğin, silinmiş sağlanan tür yalnızca statik özellikler ve üyeler içerip oluşturucu içermeyebilir, ve türün bir örneğini hiçbir yöntem ya da özellik döndürmeyebilir. Eğer bir silinmiş türün örneklerine erişebiliyorsanız, aşağıdaki soruları göz önüne almalısınız:

  • Sağlanan türün silintisi nedir?

    • Bir sağlanan türün silintisi türün derlenmiş .NET kodu içinde nasıl göründüğüdür.

    • Bir sağlanan silinmiş sınıf türünün silintisi her zaman türün kalıtım zincirindeki ilk silinmiş olmayan temel türdür.

    • Bir sağlanan silinmiş arabirim türünün silintisi her zaman Object.

  • Bir sağlanan türün temsilleri nedir?

    • Bir silinmiş sağlanan tür için olası nesneler kümesine onun temsilleri denir. Bu belgedeki örnek içinde, tüm silinmiş sağlanan türlerin Type1..Type100 türleri her zaman dize nesneleridir.

Bir sağlanan türün tüm temsilleri sağlanan türün silintisi ile uyumlu olmalıdır. (Aksi halde, ya F# derleyicisi tür sağlayıcısının kullanımı için bir hata verir, ya da geçerli olmayan doğrulanamayan .NET kodu üretilir. Bir tür sağlayıcısı eğer geçerli olmayan bir temsil veren kod döndürüyorsa geçerli değildir.)

Sağlanan nesnelere bir temsil seçmek için ikisi de yaygın olan aşağıdaki yaklaşımlardan herhangi birini kullanabilirsiniz:

  • Eğer varolan bir .NET türü üzerine basitçe bir türü kesin belirlenmiş sarmalayıcı sağlıyorsanız, genellikle türünüzün o türe silinmesi, o türü temsil olarak kullanması, ya da ikisi birden anlamlıdır. Bu yaklaşım o tür üzerinde varolan yöntemlerin çoğu türü kesin belirli olan sürüm kullanıldığında hala anlamlı oldukları zaman uygundur.

  • Eğer herhangi bir varolan .NET APIsinden önemli ölçüde farklı olan bir API oluşturmak istiyorsanız, sağlanan türler için tür silintisi ve temsil olan çalışma zamanı türleri oluşturmanız anlamlıdır.

Bu belge içindeki örnek sağlanan nesneler için temsil olarak dizeler kullanır. Sık olarak, temsiller için başka nesneler kullanmak uygun olabilir. Örneğin, bir özellik çantası olarak bir sözlük kullanabilirsiniz:

   ProvidedConstructor(parameters = [], 
                       InvokeCode= (fun args -> <@@ (new Dictionary<string,obj>()) :> obj @@>))

Alternatif olarak, tür sağlayıcınız içinde çalışma zamanında temsili oluşturacak bir tür tanımlayabilirsiniz, bir ya da daha fazla çalışma zamanı işlemi ile birlikte:

type DataObject() =
    let data = Dictionary<string,obj>()
    member x.RuntimeOperation() = data.Count

Sağlanan üyeler ardından bu nesne türünün örneklerini oluşturabilirler:

   ProvidedConstructor(parameters = [], 
                       InvokeCode= (fun args -> <@@ (new DataObject()) :> obj @@>))

Bu durumda, isteğe bağlı olarak ProvidedTypeDefinition oluştururken bu türü baseType olarak belirterek tür silintisi olarak kullanabilirsiniz.

   ProvidedTypeDefinition(…, baseType = Some typeof<DataObject> )
   …
   ProvidedConstructor(…, InvokeCode = (fun args -> <@@ new DataObject() @@>), …)

Anahtar Dersler

Önceki bölüm türler, özellikler ve yöntemler sağlayan basit bir silinti tür sağlayıcısının nasıl oluşturulduğunu açıkladı. Bu bölüm ayrıca tür silintisi kavramını bir tür sağlayıcısından silinmiş türler sağlamanın bazı avantaj ve dezavantajları ile birlikte açıkladı, ve silinmiş türlerin temsillerini ele aldı.

Statik Parametreler Kullanan Bir Tür Sağlayıcısı

Tür sağlayıcılarını statik veri ile parameterize etme yeteneği sağlayıcının herhangi bir yerel ya da uzak veri erişimine ihtiyaç duymadığı durumlarda bile pek çok ilginç senaryoyu etkinleştirir. Bu bölümde, böyle bir sağlayıcıyı bir araya getirmek için bazı temel teknikleri öğreneceksiniz.

Hh361034.collapse_all(tr-tr,VS.110).gifTür Denetimli Regex Sağlayıcısı

Düzenli ifadeler için .NET Regex kütüphanelerini aşağıdaki derleme zamanı garantileri sağlayan bir arabirim içine sarmalayan bir tür sağlayıcısı uygulamak istediğinizi düşünün:

  • Bir düzenli ifadenin geçerli olup olmadığını doğrulama.

  • Düzenli ifade içindeki herhangi bir grup adını esas alan eşleştirmeler üzerinde adlandırılmış özellikler sağlama.

Bu bölüm bu yararları sağlamak için düzenli ifade deseninin parameterize ettiği bir RegExProviderType türünü oluşturmak için nasıl tür sağlayıcıları kullanacağınızı gösterir. Eğer sağlanan desen geçerli değilse derleyici bir hata verir, ve tür sağlayıcı eşleştirmelerde adlandırılmış özellikleri kullanarak onlara erişebilmeniz için desenden grupları ayıklayabilir. Bir tür sağlayıcısı tasarladığınızda, ortaya çıkarılan APInin son kullanıcılara nasıl görüneceğini ve bu tasarımın .NET koduna nasıl çevrileceğini düşünmelisiniz. Aşağıdaki örnek alan kodunun bileşenlerini almak için böyle bir APInin nasıl kullanılacağını gösterir:

type T = RegexTyped< @"(?<AreaCode>^\d{3})-(?<PhoneNumber>\d{3}-\d{4}$)">
let reg = T()
let result = T.IsMatch("425-555-2345")
let r = reg.Match("425-555-2345").Group_AreaCode.Value //r equals "425"

Aşağıdaki örnek tür sağlayıcısının bu çağrıları nasıl çevirdiğini gösterir:

let reg = new Regex(@"(?<AreaCode>^\d{3})-(?<PhoneNumber>\d{3}-\d{4}$)")
let result = reg.IsMatch("425-123-2345")
let r = reg.Match("425-123-2345").Groups.["AreaCode"].Value //r equals "425"

Aşağıdaki noktalara dikkat edin:

  • Standart Regex türü parameterize edilmiş RegexTyped türünü temsil eder.

  • RegexTyped oluşturucusu Regex oluşturucusuna desen için statik tür bağımsız değişkenini gönderen bir çağrıya neden olur.

  • Match yöntemi sonuçları standart Match türü ile temsil edilir.

  • Her adlandırılmış grup bir sağlanan özellik ile sonuçların, ve özelliğe erişmek eşleştirmenin Groups koleksiyonu üzerinde bir dizin oluşturucu kullanımına neden olur.

Aşağıdaki kod bu tür bir sağlayıcıyı uygulamanın mantığının merkezidir, ve bu örnek sağlanan türe tüm üyelerin eklenmesini atlamıştır. Her eklenen üye ile hakkında bilgi için, bu konunun ilerleyen bölümlerindeki uygun bölüme bakın. Tam kod için, örneği Codeplex sitesindeki F# 3.0 Örnek Paketi ile indirin.

namespace Samples.FSharp.RegexTypeProvider

open System.Reflection
open Microsoft.FSharp.Core.CompilerServices
open Samples.FSharp.ProvidedTypes
open System.Text.RegularExpressions

[<TypeProvider>]
type public CheckedRegexProvider() as this =
    inherit TypeProviderForNamespaces()

    // Get the assembly and namespace used to house the provided types
    let thisAssembly = Assembly.GetExecutingAssembly()
    let rootNamespace = "Samples.FSharp.RegexTypeProvider"
    let baseTy = typeof<obj>
    let staticParams = [ProvidedStaticParameter("pattern", typeof<string>)]

    let regexTy = ProvidedTypeDefinition(thisAssembly, rootNamespace, "RegexTyped", Some baseTy)

    do regexTy.DefineStaticParameters(
        parameters=staticParams, 
        instantiationFunction=(fun typeName parameterValues ->

          match parameterValues with 
          | [| :? string as pattern|] -> 
            // Create an instance of the regular expression. 
            //
            // This will fail with System.ArgumentException if the regular expression is not valid. 
            // The exception will escape the type provider and be reported in client code.
            let r = System.Text.RegularExpressions.Regex(pattern)            

            // Declare the typed regex provided type.
            // The type erasure of this type is 'obj', even though the representation will always be a Regex
            // This, combined with hiding the object methods, makes the IntelliSense experience simpler.
            let ty = ProvidedTypeDefinition(
                        thisAssembly, 
                        rootNamespace, 
                        typeName, 
                        baseType = Some baseTy)

            ...
            
            ty
          | _ -> failwith "unexpected parameter values")) 

    do this.AddNamespace(rootNamespace, [regexTy])

[<TypeProviderAssembly>]
do ()

Aşağıdaki noktalara dikkat edin:

  • Tür sağlayıcısı iki statik parametre alır: zorunlu olan pattern, ve isteğe bağlı olan (varsayılan değer sağlandığı için) options.

  • Statik bağımsız değişkenler sağlandıktan sonra, düzenli ifadenin bir örneğini oluşturabilirsiniz. Bu örnek eğer Regex hatalı biçimlendirildiyse bir özel durum harekete geçirir, ve bu hata kullanıcılara bildirilir.

  • DefineStaticParameters geri araması içinde, bağımsız değişkenler sağlandıktan sonra döndürülecek türü belirlersiniz.

  • Bu kod HideObjectMethods doğru olarak ayarlar ve bu sayede IntelliSense deneyimi akıcı olarak devam eder. Bu öznitelik bir sağlanan nesne için Equals, GetHashCode, Finalize, ve GetType üyelerinin IntelliSense listesinde görüntülenmemesini sağlar.

  • Yöntemin temel türü olarak obj kullanırsınız, ama bu türün çalışma zamanı temsili olarak sonraki örneğin gösterdiği gibi bir Regex nesnesi kullanırsınız.

  • Regex oluşturucusu çağrısı bir düzenli ifade geçerli olmadığında bir ArgumentException harekete geçirir. Derleyici bu özel durumu yakalar ve kullanıcıya derleme zamanında ya da Visual Studio biçimlendiricisi içinde bir hata iletisi bildirir. Bu özel durum düzenli ifadelerin bir uygulama çalıştırılmadan doğrulanmasını sağlar.

Yukarıda tanımlanan tür herhangi bir anlamlı yöntem ya da özellik içermediği için henüz kullanışlı değildir. İlk olarak, bir statik IsMatch yöntemi ekleyin:

let isMatch = ProvidedMethod(
                methodName = "IsMatch", 
                parameters = [ProvidedParameter("input", typeof<string>)], 
                returnType = typeof<bool>, 
                IsStaticMethod = true,
                InvokeCode = fun args -> <@@ Regex.IsMatch(%%args.[0], pattern) @@>) 

isMatch.AddXmlDoc "Indicates whether the regular expression finds a match in the specified input string." 
ty.AddMember isMatch

Önceki kod giriş olarak bir dize alan ve bir bool döndüren bir IsMatch yöntemi tanımlar. Ustalık isteyen tek kısım InvokeCode tanımı içinde args bağımsız değişkeni kullanımıdır. Bu örnekte, args bu yönteme bağımsız değişkenleri temsil eder bir alıntı listesidir. Eğer yöntem bir örnek yöntemi ise, ilk bağımsız değişken this bağımsız değişkenini temsil eder. Ancak, bir statik yöntem için, bağımsız değişkenler yalnızca yönteme açık bağımsız değişkenlerdir. Alıntılanan değerin türünün belirtilen dönüş türüyle eşleşmesine dikkat edin (bu durumda, bool). Ayrıca bu kodun sağlanan yöntemin IntelliSense aracılığıyla sağlayabileceğiniz kullanışlı belgelemeye sahip olması için AddXmlDoc yöntemini kullandığına dikkat edin.

Sonra, Match yöntemine bir örnek ekleyin. Ancak, bu yöntem gruplara türleri kesin bir şekilde erişilebilmesi için bir sağlanan Match türünde bir değer döndürmelidir. Bu nedenle, önce Match türünü bildirirsiniz. Bu tür bir statik bağımsız değişken olarak sağlanan desene bağlı olduğu için, bu tür parameterize edilmiş tür tanımı içinde iç içe olmalıdır:

let matchTy = ProvidedTypeDefinition(
                "MatchType", 
                baseType = Some baseTy, 
                HideObjectMethods = true)

ty.AddMember matchTy

Sonra her grup için Match türüne bir özellik eklersiniz. Çalışma zamanında, bir eşleşme bir Match değeri olarak temsil edilir, bu nedenle ilgili grubu almak için özelliği tanımlayan alıntı Groups dizinlemiş özelliğini kullanmalıdır.

for group in r.GetGroupNames() do
    // Ignore the group named 0, which represents all input.
    if group <> "0" then
        let prop = ProvidedProperty(
                    propertyName = group, 
                    propertyType = typeof<Group>, 
                    GetterCode = fun args -> <@@ ((%%args.[0]:obj) :?> Match).Groups.[group] @@>)
        prop.AddXmlDoc(sprintf @"Gets the ""%s"" group from this match" group)
        matchTy.AddMember prop

Yine, sağlanan özelliğe XML belgelemesi eklediğinize dikkat edin. Ayrıca özelliğin eğer bir GetterCode işlevi sağlandıysa okunabildiğine, ve özelliğin eğer bir SetterCode işlevi sağlandıysa yazılabildiğine, ve sonuç özelliğin salt okunur olduğuna dikkat edin.

Şimdi bu Match türünün bir değerini döndüren bir örnek yöntemi oluşturabilirsiniz:

let matchMethod = 
    ProvidedMethod(
        methodName = "Match", 
        parameters = [ProvidedParameter("input", typeof<string>)], 
        returnType = matchTy, 
        InvokeCode = fun args -> <@@ ((%%args.[0]:obj) :?> Regex).Match(%%args.[1]) :> obj @@>)
matchMeth.AddXmlDoc "Searches the specified input string for the first occurrence of this regular expression" 

ty.AddMember matchMeth

Bir örnek yöntemi oluşturduğunuz için, args.[0] yöntemin üzerinde çağırıldığı RegexTyped örneğini temsil eder, ve args.[1] giriş bağımsız değişkenidir.

Son olarak, sağlanan türün örneklerinin oluşturulabilmesi için bir oluşturucu sağlayın.

let ctor = ProvidedConstructor(
            parameters = [], 
            InvokeCode = fun args -> <@@ Regex(pattern, options) :> obj @@>)
ctor.AddXmlDoc("Initializes a regular expression instance.")

ty.AddMember ctor

Oluşturucu yalnızca standart .NET Regex örneğinin oluşumuna siler, ki bu da yine bir nesneye kutulanır çünkü obj sağlanan türün silintisidir. Bu değişiklik ile, konunun önceki kısımlarında belirtilen API kullanımı beklendiği gibi çalışır. Aşağıdaki kod tam ve sondur:

namespace Samples.FSharp.RegexTypeProvider

open System.Reflection
open Microsoft.FSharp.Core.CompilerServices
open Samples.FSharp.ProvidedTypes
open System.Text.RegularExpressions

[<TypeProvider>]
type public CheckedRegexProvider() as this =
    inherit TypeProviderForNamespaces()

    // Get the assembly and namespace used to house the provided types.
    let thisAssembly = Assembly.GetExecutingAssembly()
    let rootNamespace = "Samples.FSharp.RegexTypeProvider"
    let baseTy = typeof<obj>
    let staticParams = [ProvidedStaticParameter("pattern", typeof<string>)]

    let regexTy = ProvidedTypeDefinition(thisAssembly, rootNamespace, "RegexTyped", Some baseTy)

    do regexTy.DefineStaticParameters(
        parameters=staticParams, 
        instantiationFunction=(fun typeName parameterValues ->

          match parameterValues with 
          | [| :? string as pattern|] -> 
            // Create an instance of the regular expression. 




            let r = System.Text.RegularExpressions.Regex(pattern)            

            // Declare the typed regex provided type.



            let ty = ProvidedTypeDefinition(
                        thisAssembly, 
                        rootNamespace, 
                        typeName, 
                        baseType = Some baseTy)

            ty.AddXmlDoc "A strongly typed interface to the regular expression '%s'"

            // Provide strongly typed version of Regex.IsMatch static method.
            let isMatch = ProvidedMethod(
                            methodName = "IsMatch", 
                            parameters = [ProvidedParameter("input", typeof<string>)], 
                            returnType = typeof<bool>, 
                            IsStaticMethod = true,
                            InvokeCode = fun args -> <@@ Regex.IsMatch(%%args.[0], pattern) @@>) 

            isMatch.AddXmlDoc "Indicates whether the regular expression finds a match in the specified input string"

            ty.AddMember isMatch

            // Provided type for matches
            // Again, erase to obj even though the representation will always be a Match
            let matchTy = ProvidedTypeDefinition(
                            "MatchType", 
                            baseType = Some baseTy, 
                            HideObjectMethods = true)

            // Nest the match type within parameterized Regex type.
            ty.AddMember matchTy
        
            // Add group properties to match type
            for group in r.GetGroupNames() do
                // Ignore the group named 0, which represents all input.
                if group <> "0" then
                    let prop = ProvidedProperty(
                                propertyName = group, 
                                propertyType = typeof<Group>, 
                                GetterCode = fun args -> <@@ ((%%args.[0]:obj) :?> Match).Groups.[group] @@>)
                    prop.AddXmlDoc(sprintf @"Gets the ""%s"" group from this match" group)
                    matchTy.AddMember(prop)

            // Provide strongly typed version of Regex.Match instance method.
            let matchMeth = ProvidedMethod(
                                methodName = "Match", 
                                parameters = [ProvidedParameter("input", typeof<string>)], 
                                returnType = matchTy, 
                                InvokeCode = fun args -> <@@ ((%%args.[0]:obj) :?> Regex).Match(%%args.[1]) :> obj @@>)
            matchMeth.AddXmlDoc "Searches the specified input string for the first occurence of this regular expression"
            
            ty.AddMember matchMeth
            
            // Declare a constructor.
            let ctor = ProvidedConstructor(
                        parameters = [], 
                        InvokeCode = fun args -> <@@ Regex(pattern) :> obj @@>)

            // Add documentation to the constructor.
            ctor.AddXmlDoc "Initializes a regular expression instance"

            ty.AddMember ctor
            
            ty
          | _ -> failwith "unexpected parameter values")) 

    do this.AddNamespace(rootNamespace, [regexTy])

[<TypeProviderAssembly>]
do ()

Anahtar Dersler

Bu bölüm nasıl statik parametreleri üzerinde çalışan bir tür sağlayıcısı oluşturulacağını açıkladı. Sağlayıcı statik parametreyi denetler ve değerini temel alarak işlemler sağlar.

Yerel Veri Tarafından Desteklenen Bir Tür Sağlayıcısı

Sık olarak, tür sağlayıcılarının yalnızca statik parametreleri değil, ayrıca yerel ya da uzak sistemlerden gelen bilgileri de temel alan APIler sağlamasını isteyebilirsiniz. Bu bölüm yerel veri dosyaları gibi yerel veriyi temel alan tür sağlayıcılarını anlatır.

Hh361034.collapse_all(tr-tr,VS.110).gifBasit CSV Dosyası Sağlayıcısı

Basit bir örnek olarak, Virgülle Ayrılan Değer (CSV) biçiminde bilimsel veriye erişim için bir tür sağlayıcısı düşünün. Bu bölüm CSV dosyalarının aşağıdaki tablonun gösterdiği gibi bir üstbilgi satırı ve ardından kayan nokta verisi içerdiğini varsayar:

Uzaklık (metre)

Süre (saniye)

50.0

3.7

100.0

5.2

150.0

6.4

Bu bölüm satırları float<meter> türünde bir Distance özelliği ve float<second> türünde bir Time özelliği ile almakta kullanacağınız bir türü nasıl oluşturacağınızı gösterir. Kolaylık olması açısından, aşağıdaki varsayımlar yapılmıştır:

  • Üstbilgi adları us birimsizdir ya da "Ad (birim)" biçimine sahiptir ve virgül içermez.

  • Birimlerin hepsi Microsoft.FSharp.Data.UnitSystems.SI.UnitNames Modülü (F#) modülünün tanımladığı gibi Systeme International (SI) birimleridir.

  • Birimlerin hepsi bileşik (örneğin, metre/saniye) olmak yerine basittir (örneğin, metre).

  • Tüm sütunlar kayan nokta verisi içerir.

Daha kapsamlı bir sağlayıcı bu kısıtlamaları gevşetir.

Yine ilk adım API'nin nasıl görüneceğini göz önünde bulundurmaktır. Verilen bir info.csv dosya içeriğiyle önceki tablodaki (virgülle ayrılmış biçim) sağlayıcısının kullanıcılar aşağıdaki örneğe benzer bir kod yazmak görebilmeniz gerekir:

let info = new MiniCsv<"info.csv">()
for row in info.Data do
    let time = row.Time
    printfn "%f" (float time)

Bu durumda, derleyici bu çağrıları aşağıdaki örnek gibi bir şeye dönüştürmelidir:

let info = new MiniCsvFile("info.csv")
for row in info.Data do
    let (time:float) = row.[1]
    printfn "%f" (float time)

En iyi çeviri tür sağlayıcının derlemesinde gerçek bir CsvFile türü tanımlamasını gerektirir. Tür sağlayıcıları önemli mantığı sarmalamak için genellikle birkaç yardımcı türler ve yöntemler kullanır. Ölçümler çalışma zamanında silindiği için, bir satır için silinmiş tür olarak bir float[] kullanabilirsiniz. Derleyici farklı sütunları farklı ölçüm türlerine sahip olarak değerlendirecektir. Örneğin, öreğimizdeki ilk sütun float<meter>, ikinci sütun float<second> türüne sahiptir. Ancak, silinmiş temsiller oldukça basit kalabilir.

Aşağıdaki kod uygulamanın çekirdeğini gösterir.

// Simple type wrapping CSV data
type CsvFile(filename) =
    // Cache the sequence of all data lines (all lines but the first)
    let data = 
        seq { for line in File.ReadAllLines(filename) |> Seq.skip 1 do
                yield line.Split(',') |> Array.map float }
        |> Seq.cache
    member __.Data = data

[<TypeProvider>]
type public MiniCsvProvider(cfg:TypeProviderConfig) as this =
    inherit TypeProviderForNamespaces()

    // Get the assembly and namespace used to house the provided types.
    let asm = System.Reflection.Assembly.GetExecutingAssembly()
    let ns = "Samples.FSharp.MiniCsvProvider"

    // Create the main provided type.
    let csvTy = ProvidedTypeDefinition(asm, ns, "MiniCsv", Some(typeof<obj>))

    // Parameterize the type by the file to use as a template.
    let filename = ProvidedStaticParameter("filename", typeof<string>)
    do csvTy.DefineStaticParameters([filename], fun tyName [| :? string as filename |] ->

        // Resolve the filename relative to the resolution folder.
        let resolvedFilename = Path.Combine(cfg.ResolutionFolder, filename)
        
        // Get the first line from the file.
        let headerLine = File.ReadLines(resolvedFilename) |> Seq.head

        // Define a provided type for each row, erasing to a float[].
        let rowTy = ProvidedTypeDefinition("Row", Some(typeof<float[]>))

        // Extract header names from the file, splitting on commas.
        // use Regex matching to get the position in the row at which the field occurs
        let headers = Regex.Matches(headerLine, "[^,]+")

        // Add one property per CSV field.
        for i in 0 .. headers.Count - 1 do
            let headerText = headers.[i].Value
            
            // Try to decompose this header into a name and unit.
            let fieldName, fieldTy =
                let m = Regex.Match(headerText, @"(?<field>.+) \((?<unit>.+)\)")
                if m.Success then


                    let unitName = m.Groups.["unit"].Value
                    let units = ProvidedMeasureBuilder.Default.SI unitName
                    m.Groups.["field"].Value, ProvidedMeasureBuilder.Default.AnnotateType(typeof<float>,[units])


                else
                    // no units, just treat it as a normal float
                    headerText, typeof<float>

            let prop = ProvidedProperty(fieldName, fieldTy, 
                                             GetterCode = fun [row] -> <@@ (%%row:float[]).[i] @@>)

            // Add metadata that defines the property's location in the referenced file.
            prop.AddDefinitionLocation(1, headers.[i].Index + 1, filename)
            rowTy.AddMember(prop) 
                
        // Define the provided type, erasing to CsvFile.
        let ty = ProvidedTypeDefinition(asm, ns, tyName, Some(typeof<CsvFile>))

        // Add a parameterless constructor that loads the file that was used to define the schema.
        let ctor0 = ProvidedConstructor([], 
                                        InvokeCode = fun [] -> <@@ CsvFile(resolvedFilename) @@>)
        ty.AddMember ctor0

        // Add a constructor that takes the file name to load.
        let ctor1 = ProvidedConstructor([ProvidedParameter("filename", typeof<string>)], 
                                        InvokeCode = fun [filename] -> <@@ CsvFile(%%filename) @@>)
        ty.AddMember ctor1
        
        // Add a more strongly typed Data property, which uses the existing property at runtime.
        let prop = ProvidedProperty("Data", typedefof<seq<_>>.MakeGenericType(rowTy), 
                                    GetterCode = fun [csvFile] -> <@@ (%%csvFile:CsvFile).Data @@>)
        ty.AddMember prop

        // Add the row type as a nested type.
        ty.AddMember rowTy
        ty)

    // Add the type to the namespace.
    do this.AddNamespace(ns, [csvTy])

Uygulama hakkında aşağıdaki noktaları göz önünde bulundurun:

  • Aşırı yüklenmiş oluşturucular ya orijinal dosyanın ya da özdeş bir şemaya sahip olan dosyanın okunmasına izin verir. Bu desen yerel ya da uzak veri kaynakları için bir tür sağlayıcısı yazarken yaygındır, ve bu desen bir yerel dosyanın uzak veri için şablon olarak kullanımına izin verir.

    Göreli dosya adlarını çözümlemek için tür sağlayıcısı oluşturucusu içine gönderilen TypeProviderConfig değerini kullanabilirsiniz.

  • Sağlanan özelliklerin konumunu tanımlamak için AddDefinitionLocation yöntemini kullanabilirsiniz. Bu nedenle, eğer bir sağlanan değer üzerinde Go To Definition kullanırsanız, CSV dosyası Visual Studio içinde açılır.

  • ProvidedMeasureBuilder türünü SI birimlerine bakmak ve ilgili float<_> türlerini üretmek için kullanabilirsiniz.

Anahtar Dersler

Bu bölüm veri kaynağının kendisi içinde bulunan basit bir şema ile nasıl yerel bir veri kaynağı için bir tür sağlayıcısı oluşturulduğunu açıkladı.

Daha İlerisi

Aşağıdaki bölümler daha ileri çalışmalar için öneriler içerir.

Hh361034.collapse_all(tr-tr,VS.110).gifSilinmiş Türler için Derlenen Koda Bir Bakış

Tür sağlayıcısı kullanımının yayılan koda nasıl karşılık geldiği hakkında size bazı fikirler vermesi için, bu konuda daha önce kullanılan HelloWorldTypeProvider kullanarak aşağıdaki fonksiyona bakın:

let function1 () = 
    let obj1 = Samples.HelloWorldTypeProvider.Type1("some data")
    obj1.InstanceProperty

Aşağıda ildasm.exe kullanarak geri derlenen sonuç kodun bir görüntüsü vardır:

.class public abstract auto ansi sealed Module1
       extends [mscorlib]System.Object
{
  .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAtt
ribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags)
= ( 01 00 07 00 00 00 00 00 )
  .method public static int32  function1() cil managed
  {
    // Code size       24 (0x18)
    .maxstack  3
    .locals init ([0] object obj1)
    IL_0000:  nop
    IL_0001:  ldstr      "some data"
    IL_0006:  unbox.any  [mscorlib]System.Object
    IL_000b:  stloc.0
    IL_000c:  ldloc.0
    IL_000d:  call       !!0 [FSharp.Core_2]Microsoft.FSharp.Core.LanguagePrimit
ives/IntrinsicFunctions::UnboxGeneric<string>(object)
    IL_0012:  callvirt   instance int32 [mscorlib_3]System.String::get_Length()
    IL_0017:  ret
  } // end of method Module1::function1

} // end of class Module1

Örneğin gösterdiği gibi, Type1 türü ve InstanceProperty özelliğinin tüm bahisleri silinmiştir, ve geriye sadece ilgili çalışma zaman türleri üzerinde işlemler kalmıştır.

Hh361034.collapse_all(tr-tr,VS.110).gifTür Sağlayıcıları için Tasarım ve Adlandırma Kuralları

Tür sağlayıcıları yazarken aşağıdaki kuralları gözlemleyin.

  • Bağlantı Protokolleri için Sağlayıcılar

    Genellikle, çoğu veri ve hizmet bağlantı protokolleri için (OData ya da SQL bağlantıları gibi) sağlayıcı DLL isimleri TypeProvider ya da TypeProviders ile sona ermelidir. Örneğin, aşağıdaki dizeye benzeyen bir DLL adı kullanın:

    Fabrikam.Management.BasicTypeProviders.dll
    

    Sağlanan türlerinizin karşılık gelen ad alanının üyeleri olduklarından emin olun, ve uyguladığınız bağlantı protokolünü belirtin:

    Fabrikam.Management.BasicTypeProviders.WmiConnection<…>
    Fabrikam.Management.BasicTypeProviders.DataProtocolConnection<…>
    
  • Genel Kodlama için Yardımcı Sağlayıcılar

    Düzenli ifadeler için olanlar gibi bir yardımcı tür sağlayıcısı için, tür sağlayıcısı aşağıdaki örneğin gösterdiği gibi bir temel kitaplığın parçası olabilir:

    #r "Fabrikam.Core.Text.Utilities.dll"
    

    Bu durumda, sağlanan tür normal .NET tasarım kurallarına göre uygun bir noktada görünür:

    open Fabrikam.Core.Text.RegexTyped
    
    let regex = new RegexTyped<"a+b+a+b+">()
    
  • Singleton Veri Kaynakları

    Bazı tür sağlayıcıları tek bir özel veri kaynağına bağlanıp yalnızca veri sağlar. Bu durumda, TypeProvider son ekini bırakıp .NET adlandırması için normal kuralları kullanın:

    #r "Fabrikam.Data.Freebase.dll"
    
    let data = Fabrikam.Data.Freebase.Astronomy.Asteroids
    

    Daha fazla bilgi için, bu konuda daha sonra açıklanan GetConnection tasarım kurallarına bakın.

Hh361034.collapse_all(tr-tr,VS.110).gifTür Sağlayıcıları için Tasarım Desenleri

Aşağıdaki bölümler tür sağlayıcıları yazarken kullanabileceğiniz tasarım desenlerini açıklar.

Hh361034.collapse_all(tr-tr,VS.110).gifGetConnection Tasarım Deseni

Çoğu tür sağlayıcısı FSharp.Data.TypeProviders.dll içindeki tür sağlayıcıları tarafından kullanılan GetConnection tasarımını kullanacak şekilde yazılmalıdır, aşağıdaki örneği gösterdiği gibi:

#r "Fabrikam.Data.WebDataStore.dll"

type Service = Fabrikam.Data.WebDataStore<…static connection parameters…>

let connection = Service.GetConnection(…dynamic connection parameters…)

let data = connection.Astronomy.Asteroids

Hh361034.collapse_all(tr-tr,VS.110).gifUzak Veri ve Hizmetler ile Desteklenen Tür Sağlayıcıları

Uzak veri ve hizmetler tarafından desteklenen bir tür sağlayıcısı oluşturmadan önce, bağlı programlamanın doğasında bulunan bazı durumları dikkate almanız gereklidir. Bu durumlar aşağıdaki değerlendirmeleri içerir:

  • şema eşleme

  • şema değişikliği durumunda canlılık ve doğrulama

  • şema önbelleğe alma

  • veri erişim işlemlerinin zaman uyumsuz uygulamaları

  • LINQ sorguları dahil olmak üzere sorguları destekleme

  • kimlik ve kimlik doğrulama

Bu konu bu durumları daha detaylı incelemez.

Hh361034.collapse_all(tr-tr,VS.110).gifEk Yazma Teknikleri

Kendi tür sağlayıcılarınızı yazdığınızda, aşağıdaki ek teknikleri kullanmak isteyebilirsiniz.

  • İstek Anında Türler ve Üyeler Oluşturmak

    ProvidedType APIsi AddMember için gecikmeli sürümlere sahiptir.

    type ProvidedType =
        member AddMemberDelayed  : (unit -> MemberInfo)      -> unit
        member AddMembersDelayed : (unit -> MemberInfo list) -> unit
    

    Bu sürümler istek anında üretilen tür uzayları oluşturmakta kullanılır.

  • Array, ByRef ve Pointer türleri sağlama

    Herhangi bir System.Type örneği üzerinde, ProvidedTypeDefinitions dahil, normal MakeArrayType, MakePointerType ve MakeGenericType kullanarak sağlanan üyeler (imzaları array türlerini, byref türlerini ve genel türlerin örneklemelerini içeren) yapabilirsiniz.

  • Ölçü Birimi Açıklamaları Sağlama

    ProvidedTypes APIsi ölçü açıklamaları sağlamak için yardımcılar sağlar. Örneğin, float<kg> türü sağlamak için, aşağıdaki kodu kullanın:

    let measures = ProvidedMeasureBuilder.Default
    let kg = measures.SI "kilogram"
    let m = measures.SI "meter"
    let float_kg = measures.AnnotateType(typeof<float>,[kg])
    

    Nullable<decimal<kg/m^2>> türü sağlamak için, aşağıdaki kodu kullanın:

    let kgpm2 = measures.Ratio(kg, measures.Square m)
    let dkgpm2 = measures.AnnotateType(typeof<decimal>,[kgpm2])
    let nullableDecimal_kgpm2 = typedefof<System.Nullable<_>>.MakeGenericType [|dkgpm2 |]
    
  • Proje-Yerel ya da Betik-Yerel Kaynaklara Erişme

    Bir tür sağlayıcısının her türüne oluşturma esnasında bir TypeProviderConfig değeri verilebilir. Bu değer sağlayıcı için "çözüm klasörü" (yani, derleme için proje klasörü ya da bir betik içeren dizin), başvurulan derlemeler listesi ve diğer bilgileri içerir.

  • Geçersizlik

    Sağlayıcılar F# dil hizmetine şema varsayımlarının değişmiş olabileceğini bildirmek için geçersizlik sinyalleri yükseltebilir. Geçersizlik ortaya çıktığında, eğer sağlayıcı Visual Studio içinde çalıştırılıyorsa yeniden bir tür denetimi yapılır. Bu sinyal eğer sağlayıcı F# Interactive ya da F# Derleyici (fsc.exe) içinde çalıştırılıyorsa yoksayılır.

  • Şema Bilgilerini Önbelleğe Alma

    Sağlayıcılar genellikle şema bilgilerine erişimi önbelleğe almak zorundadır. Önbelleğe alınan veri bir statik parametre ya da kullanıcı verisi olarak verilen bir dosya adı ile saklanmalıdır. Şema önbelleğe almanın bir örneği FSharp.Data.TypeProviders derlemesi içindeki tür sağlayıcılar içindeki LocalSchemaFile parametresidir. Bu sağlayıcıların uygulaması içinde, statik parametre tür sağlayıcısını veri kaynağına ağ üzerinden erişmek yerine belirtilen yerel dosya içindeki şema bilgisini kullanmaya yönlendirir. Önbelleğe alınmış şema bilgilerini kullanmak için, ayrıca ForceUpdate statik parametresini de false olarak ayarlamalısınız. Benzer bir tekniği kullanarak çevrimiçi ve çevrimdışı veri erişimi sağlayabilirsiniz.

  • Destek Derlemesi

    Bir .dll ya da .exe dosyasını derlediğinizde, üretilen türler için destek .dll dosyası sonuç derlemeye statik olarak bağlanır. Bu bağlantı Ara Dil (IL) tür tanımlarını ve tüm yönetilen kaynakları destek derlemesinden son derlemeye kopyalayarak oluşturulur. F# Interactive kullandığınızda, destek .dll dosyası kopyalanmaz ve onun yerine F# Interactive işlemine doğrudan yüklenir.

  • Tür Sağlayıcılarından Özel Durumlar ve Tanılama

    Sağlanan türlerden tüm üyelerin tüm kullanımları özel durumlar harekete geçirebilir. Tüm durumlarda, eğer bir tür sağlayıcısı bir özel durum harekete geçirirse, ana derleyici hatayı belirli bir tür sağlayıcısına bağlar.

    • Tür sağlayıcısı özel durumları asla iç derleyici hatalarına neden olmamalıdır.

    • Tür sağlayıcıları uyarılar bildiremez.

    • Bir tür sağlayıcı F# derleyicisi, bir F# geliştirme ortamı ya da F# Interactive içinde çalıştırıldığında, o sağlayıcıdaki tüm özel durumlar yakalanır. Message özelliği her zaman hata metnidir, ve yığın izi görünmez. Eğer bir özel durum harekete geçirecekseniz, aşağıdaki örnekleri harekete geçirebilirsiniz:

Hh361034.collapse_all(tr-tr,VS.110).gifÜretilen Türler Sağlama

Şimdiye kadar, bu belge nasıl silinmiş türler sağlanacağını açıkladı. F# içindeki tür sağlayıcısı mekanizmasını ayrıca kullanıcının programı içine gerçek .NET tür tanımları olarak eklenen üretilen türler sağlamakta da kullanabilirsiniz. Üretilen sağlanan türlere bir tür tanımı kullanarak başvurmanız gereklidir.

open Microsoft.FSharp.TypeProviders 

type Service = ODataService<" http://services.odata.org/Northwind/Northwind.svc/">

F# 3.0 sürümünün parçası olan ProvidedTypes-0.2 yardımcı kodu üretilen türler sağlamak için yalnızca sınırlı desteğe sahiptir. Bir üretilen tür tanımı için aşağıdaki ifadeler doğru olmalıdır:

  • IsErased false olarak ayarlanmış olmalıdır.

  • Tür sağlayıcısı disk üzerinde eşleşen bir .dll dosyası ile gerçek bir destek .NET .dll dosyasına sahip olan bir derlemeye sahip olmalıdır.

Ayrıca iç içe türleri bir kapalı üretilen tür kümesi oluşturan bir kök sağlanan tür üzerine ConvertToGenerated çağırmanız gereklidir. Bu çağrı verilen sağlanan tür tanımını ve onun iç içe tür tanımlarını bir derleme içine yayar ve o derlemeyi döndürmek için tüm sağlanan tür tanımlarının Assembly özelliklerini ayarlar. Derleme yalnızca kök tür üzerindeki Assembly özelliği ilk defa erişildiğinde yayılır. Ana F# derleyicisi tür için bir üretimsel tür bildirimi işlerken bu özelliğe erişir.

Kurallar ve Sınırlamalar

Tür sağlayıcıları yazdığınızda, aşağıdaki kuralları ve sınırlamaları aklınızda bulundurun.

  • Sağlanan türler erişilebilir olmalıdır.

    Tüm sağlanan türler iç içe olmayan türler tarafından erişilebilir olmalıdır. İç içe olmayan türler TypeProviderForNamespaces oluşturucusu çağrısı içinde ya da bir AddNamespace çağrısı içinde verilir. Örneğin, eğer sağlayıcı bir StaticClass.P : T türü sağlarsa, T'nin ya iç içe olmayan bir tür olduğundan ya da bir iç içe olmayan bir tür altında iç içe olduğundan emin olmanız gerekir.

    Örneğin, bazı sağlayıcılar bu T1, T2, T3, ... türlerini içeren DataTypes gibi bir statik sınıfa sahiptir. Aksi halde, hata A derlemesi içinde T türüne bir başvuru bulunduğunu ama türün o derleme içinde bulunamadığını söyler. Eğer bu hata görüntülenirse, tüm alttürlerinizin sağlanan türlerden erişilebildiğini doğrulayın. Not: Bu T1, T2, T3... türleri anlık türler olarak adlandırılır. Onları erişilebilir bir ad alanı ya da bir üst tür içine koymayı unutmayın.

  • Tür Sağlayıcısı Mekanizmasının Sınırlamaları

    F# içinde tür sağlayıcı mekanizması aşağıdaki sınırlamalara sahiptir:

    • F# içindeki tür sağlayıcıları için temel altyapı sağlanan genel türleri ya da sağlanan genel yöntemleri desteklemez.

    • Mekanizma statik parametreler ile iç içe türleri desteklemez.

  • ProvidedTypes Destek Kodunun Sınırlamaları

    ProvidedTypes destek kodu aşağıdaki kural ve sınırlamalara sahiptir:

    1. Dizinlenmiş alıcı ve ayarlayıcılar ile sağlanan özellikler uygulanmamıştır.

    2. Sağlanan olaylar uygulanmamıştır.

    3. Sağlanan türler ve bilgi nesneleri yalnızca F# içindeki tür sağlayıcısı mekanizması için kullanılmalıdır. System.Type nesneleri gibi daha genel olarak kullanılabilir değillerdir.

    4. Yöntem uygulamalarını tanımlayan alıntılar içinde kullanabildiğiniz yapılar bazı kısıtlamalara sahiptir. Hangi yapıların alıntılar içinde desteklendiğini görmek için ProvidedTypes-Sürüm için kaynak koduna başvurabilirsiniz.

  • Sağlayıcı türü dosyaların .dll, .exe dosyaları çıktı derlemeleri oluşturmanız gerekir.

Geliştirme İpuçları

Aşağıdaki ipuçlarını geliştirme sürecinde yararlı bulabilirsiniz.

  • Visual Studio'nun İki Örneğini Çalıştırma Bir örnek içinde tür sağlayıcısını geliştirip diğer örnek içinde sağlayıcıyı sınayabilirsiniz, çünkü sınama IDE'si .dll dosyası üzerinde tür sağlayıcısının yeniden derlenmesini engelleyen bir kilit alır. Bu nedenle, ilk örnekte sağlayıcı derlenirken Visual Studio'nun ikinci örneğini kapatmalı, ve sağlayıcı derlendikten sonra ikinci örneği yeniden açmalısınız.

  • Tür sağlayıcılarını fsc.exe çağrıları kullanarak hata ayıklama Aşağıdaki araçları kullanarak tür sağlayıcılarını çağırabilirsiniz:

    • fsc.exe (F# komut satırı derleyicisi)

    • fsi.exe (F# Interactive derleyicisi)

    • devenv.exe (Visual Studio)

    Tür sağlayıcılarını genellikle en kolay fsc.exe'yi bir sınama betik dosyası (örneğin, betik.fsx) üzerinde kullanarak hata ayıklayabilirsiniz. Bir komut satırından bir hata ayıklayıcı başlatabilirsiniz.

    devenv /debugexe fsc.exe script.fsx
    

    Print-to-stdout günlükleme kullanabilirsiniz.

Ayrıca bkz.

Diğer Kaynaklar

Sağlayıcı türü