Öğretici: Tür Sağlayıcısı Oluşturma
F# dilindeki tür sağlayıcısı mekanizması, bilgi açısından zengin programlama desteğinin önemli bir kısmıdır. Bu öğreticide, temel kavramları göstermek için birkaç basit tür sağlayıcısının geliştirilmesinde size yol göstererek kendi tür sağlayıcılarınızı nasıl oluşturabilirsiniz? F# içinde tür sağlayıcısı mekanizması hakkında daha fazla bilgi için bkz. Tür Sağlayıcıları.
F# ekosistemi, yaygın olarak kullanılan İnternet ve kurumsal veri hizmetleri için bir dizi tür sağlayıcısı içerir. Örneğin:
FSharp.Data, JSON, XML, CSV ve HTML belge biçimleri için tür sağlayıcıları içerir.
SwaggerProvider, OpenApi 3.0 ve Swagger 2.0 şemaları tarafından açıklanan API'ler için nesne modeli ve HTTP istemcileri oluşturan iki gensel tür sağlayıcısı içerir.
FSharp.Data.SqlClient, F# içinde T-SQL derleme zamanı denetlenen ekleme için bir tür sağlayıcıları kümesine sahip.
Özel tür sağlayıcıları oluşturabilir veya başkalarının oluşturduğu tür sağlayıcılarına başvurabilirsiniz. Örneğin, kuruluşta her biri kendi kararlı veri şemasına sahip çok sayıda adlandırılmış veri kümesi sağlayan bir veri hizmeti olabilir. Şemaları okuyabilen ve geçerli veri kümelerini kesin olarak türü kesin olarak yazarak programcıya sunan bir tür sağlayıcısı oluşturabilirsiniz.
Başlamadan Önce
Tür sağlayıcısı mekanizması öncelikli olarak F# programlama deneyimine kararlı veri ve hizmet bilgi alanları ekleme için tasarlanmıştır.
Bu mekanizma, program yürütme sırasında program mantığıyla ilgili yollarla şeması değişikliklerini olan bilgi alanlarını eklemeye uygun şekilde tasarlanmaz. Ayrıca, bu etki alanı bazı geçerli kullanımlar içeriyor olsa bile mekanizma dil içi meta programlama için tasarlanmamaktadır. Bu mekanizmayı yalnızca gerektiğinde ve bir tür sağlayıcısının geliştirmesi çok yüksek değer veren yerde kullanabilirsiniz.
Şemanın kullanılabilir olduğu bir tür sağlayıcısı yazmaktan kaçınmalısınız. Benzer şekilde, sıradan (hatta mevcut bir) .NET kitaplığının yeterli olduğu bir tür sağlayıcısı yazmaktan kaçınmanız gerekir.
Başlamadan önce aşağıdaki soruları sorsanız iyi olur:
Bilgi kaynağınız için bir şemanız var mı? Öyleyse, F# ve .NET tür sistemine eşleme nedir?
Mevcut (dinamik olarak türü oluşturulmuş) bir API'yi, uygulamanıza başlangıç noktası olarak kullanabilir misiniz?
Siz ve kuruluş tür sağlayıcısını yazmaya değecek kadar kullanıyor musunuz? Normal bir .NET kitaplığı, ihtiyaçlarını karşılar mı?
Şemanız ne kadar değişecek?
Kodlama sırasında değişecek mi?
Kodlama oturumları arasında değişir mi?
Program yürütme sırasında değişecek mi?
Tür sağlayıcıları, şemanın çalışma zamanında ve derlenmiş kodun kullanım ömrü boyunca kararlı olduğu durumlar için en uygun olandır.
Basit tür sağlayıcısı
Bu örnek, F# Tür Sağlayıcısı SDK'sı dizininde yer alan örneklere benzer şekilde Samples.HelloWorldTypeProvider'dır. examples Sağlayıcı, aşağıdaki kod F# imza söz dizimi kullanarak ve dışındakilerin ayrıntılarını atarak 100 silinmiş türü içeren bir "tür alanı" Type1 sağlar. Silinen türler hakkında daha fazla bilgi için bu konunun devamlarında Yer alan Silinen Sağlanan Türler Hakkında Ayrıntılar'a bakın.
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
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ümesi statik olarak bilinir. Bu örnek, sağlayıcıların şemaya bağımlı türler sağlama özelliğine sahip değildir. Tür sağlayıcısının uygulaması aşağıdaki kodda açıklanmıştır ve ayrıntılar bu konunun sonraki bölümlerinde açıklanmıştır.
Uyarı
Bu kod ile çevrimiçi örnekler arasında farklar olabilir.
namespace Samples.FSharp.HelloWorldTypeProvider
open System
open System.Reflection
open ProviderImplementation.ProvidedTypes
open FSharp.Core.CompilerServices
open 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(config)
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, Visual Studio bir F# betiği oluşturun ve aşağıdaki kodda da olduğu gibi #r kullanarak betiğinizin sağlayıcısına 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, tür sağlayıcısının Samples.HelloWorldTypeProvider oluşturulan ad alanı altında türleri arama.
Sağlayıcıyı yeniden derlemeden önce, sağlayıcı DLL'lerini kullanan tüm Visual Studio ve F# Etkileşimli örneklerini kapatmış olduğundan emin olun. Aksi takdirde, çıkış DLL'si kilitlenirken bir derleme hatası oluşur.
Yazdırma deyimlerini kullanarak bu sağlayıcıda hata ayıklamak için sağlayıcıyla ilgili bir sorunu ortaya çıkaran bir betik yapın ve ardından aşağıdaki kodu kullanın:
fsc.exe -r:bin\Debug\HelloWorldTypeProvider.dll script.fsx
Visual Studio kullanarak bu sağlayıcıda hata ayıklamak için, Geliştirici Komut İstemi için Visual Studio bilgilerini 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 menüsünü açın, öğesini seçin ve betiğinizi düzenlerken başka bir Debug/Attach to process… devenv işleme ekleyebilirsiniz. Bu yöntemi kullanarak, ifadeleri ikinci örneğine etkileşimli olarak yazarak (tam IntelliSense ve diğer özelliklerle) tür sağlayıcısında belirli mantığı daha kolay hedef alabilirsiniz.
Oluşturulan kodda hataları Yalnızca kendi kodum için hata ayıklamayı devre dışı abilirsiniz. Bu özelliği etkinleştirme veya devre dışı bırakma hakkında bilgi için bkz. Hata Ayıklayıcı ile Kodda Gezinme. Ayrıca, menüyü açıp Debug veya Ctrl+Alt+E tuşlarını seçerek iletişim kutusunu açarak ilk şans özel durum Exceptions Exceptions yakalamayı da ayarlayabilirsiniz. Bu iletişim kutusunda, altında Common Language Runtime Exceptions onay Thrown kutusunu seçin.
Tür Sağlayıcısının Uygulanması
Bu bölüm, tür sağlayıcısı uygulamasının temel bölümlerinde size yol gösterir. İlk olarak, özel tür sağlayıcısının kendisi için türü tanımlarsiniz:
[<TypeProvider>]
type SampleTypeProvider(config: TypeProviderConfig) as this =
Bu tür genel olmalı ve ayrı bir F# projesi türü içeren derlemeye başvuracaksa derleyicinin tür sağlayıcısını tanıması için TypeProvider özniteliğiyle işaretlemeniz gerekir. Config parametresi isteğe bağlıdır ve varsa, F# derleyicinin oluşturduğu tür sağlayıcısı örneği için bağlamsal yapılandırma bilgilerini içerir.
Ardından, ITypeProvider arabirimini uygulayabilirsiniz. Bu durumda API'den TypeProviderForNamespaces türünü temel tür olarak ProvidedTypes kullanırsınız. Bu yardımcı türü, her biri doğrudan sınırlı sayıda sabit ve merakla sağlanan türler içeren, hevesle sağlanan ad alanlarının sınırlı bir koleksiyonunu sağlar. Bu bağlamda sağlayıcı, gerekli veya kullanılmasa bile türleri merakla üretir.
inherit TypeProviderForNamespaces(config)
Ardından, sağlanan türler için ad alanını belirten yerel özel değerleri tanımlayın ve tür sağlayıcısı derlemenin kendisini bulun. Bu derleme daha sonra sağlanan silinen türlerin mantıksal üst türü olarak kullanılır.
let namespaceName = "Samples.HelloWorldTypeProvider"
let thisAssembly = Assembly.GetExecutingAssembly()
Ardından Type1... türlerinin her bir türünü sağlamak için bir işlev oluşturun. Tür100. Bu işlev, bu konunun devamlarında daha ayrıntılı olarak açıklanmıştır.
let makeOneProvidedType (n:int) = …
Ardından, sağlanan 100 türü üretin:
let types = [ for i in 1 .. 100 -> makeOneProvidedType i ]
Ardından, türleri sağlanan ad alanı olarak ekleyin:
do this.AddNamespace(namespaceName, types)
Son olarak, bir tür sağlayıcısı DLL'si oluşturmakta olduğunu belirten bir derleme özniteliği ekleyin:
[<assembly:TypeProviderAssembly>]
do()
Tek bir tür ve üyeleri sağlama
işlevi, makeOneProvidedType türlerden birini sağlama konusunda gerçek bir çalışma 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, Type1, when n = 1 veya Type57, when n = 57).
// 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 noktaları not alasınız:
Bu sağlanan tür silinir. Temel türün olduğunu
objbelirttiklerinden, örnekler derlenmiş kodda obj türünün değerleri olarak görünür.İç içe olmayan bir tür belirttiğinizde, derlemeyi ve ad alanını belirtmeniz gerekir. Silinen türler için derleme, tür sağlayıcısı derlemesi olmalı.
Ardından, türe XML belgeleri ekleyin. Bu belge gecikmelidir, yani konak derleyiciye ihtiyaç varsa isteğe bağlı olarak hesaplanır.
t.AddXmlDocDelayed (fun () -> $"""This provided type {"Type" + string n}""")
Ardından, sağlanan statik özelliği türüne eklersiniz:
let staticProp = ProvidedProperty(propertyName = "StaticProperty",
propertyType = typeof<string>,
isStatic = true,
getterCode = (fun args -> <@@ "Hello!" @@>))
Bu özelliği almak her zaman "Hello!" dizesi olarak değerlendirilir. özelliği için, özelliği almak için konak derleyicisi tarafından oluşturulan kodu temsil eden bir GetterCode F# teklifi kullanır. Tırnaklar hakkında daha fazla bilgi için bkz. Kod Tırnakları (F#).
özelliğine XML belgeleri ekleyin.
staticProp.AddXmlDocDelayed(fun () -> "This is a static property")
Şimdi sağlanan özelliği sağlanan türe iliştirin. Sağlanan bir üyeyi bir ve yalnızca bir türe eklemelisiniz. Aksi takdirde, üyeye hiçbir zaman erişilemez.
t.AddMember staticProp
Şimdi parametre alan bir sağlanan oluşturucu oluşturun.
let ctor = ProvidedConstructor(parameters = [ ],
invokeCode = (fun args -> <@@ "The object data" :> obj @@>))
oluşturucusu için, konak derleyicinin oluşturucu çağrıldıkta oluştur ettiği kodu InvokeCode temsil eden bir F# teklifi döndürür. Örneğin, aşağıdaki oluşturucusu kullanabilirsiniz:
new Type10()
Sağlanan türün bir örneği temel alınan "Nesne verileri" ile oluşturulur. Belirtilen kod, belirtilen türün (sağlanan türü belirttiğinizde belirttiğiniz gibi) silme işlemi olduğundan obj'ye dönüştürme içerir.
Oluşturucuya XML belgeleri ekleyin ve sağlanan oluşturucunu 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şturucusu için yöntemine yapılan bir çağrı için konak derleyicisi tarafından oluşturulan kodu temsil eden bir InvokeCode F# tırnak döndürür. Örneğin, aşağıdaki oluşturucusu kullanabilirsiniz:
new Type10("ten")
Sağlanan türün bir örneği temel alınan "on" veriyle oluşturulur. İşlevin bir tırnak döndüren InvokeCode bir şey olduğunu zaten fark etmişsinizdir. Bu işleve yapılan giriş, her oluşturucu parametresi için bir ifade listesidir. Bu durumda, içinde tek parametre değerini temsil eden bir ifade args[0] kullanılabilir. Oluşturucuya yapılan bir çağrının kodu, döndürülen değeri silinen türe zorlar obj . İkinci sağlanmış oluşturucuyu türe ekledikten sonra, bir sağlanmış ö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ğin alınması, Gösterim nesnesi olan dize uzunluğunu döndürür. GetterCodeÖzelliği, ana bilgisayar derleyicisinin özelliği almak için oluşturduğu kodu belirten bir F # teklifini döndürür. Benzer şekilde InvokeCode , GetterCode işlev bir alıntı döndürür. Ana bilgisayar derleyicisi, bu işlevi bir bağımsız değişken listesiyle çağırır. Bu durumda, bağımsız değişkenler yalnızca, alıcı çağrıldığında, kullanarak erişebileceğiniz örneği temsil eden tek bir ifade içerir args[0] . GetterCodeDaha sonra, silinen türdeki sonuç teklifine daha sonra uygulanması obj ve derleyicinin nesnenin bir dize olduğu türleri denetlemek için mekanizmayı karşılamak üzere bir dönüştürme kullanılır. Bir sonraki bölümü, makeOneProvidedType tek parametreli 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 geçmiş özellikler içeren bir iç içe türü oluşturun. Bu iç içe türün oluşturulması ve özellikleri gecikmiştir, diğer bir deyişle isteğe bağlı olarak hesaplanır.
t.AddMembersDelayed(fun () ->
let nestedType = ProvidedTypeDefinition("NestedType", Some typeof<obj>)
nestedType.AddMembersDelayed (fun () ->
let staticPropsInNestedType =
[
for i in 1 .. 100 ->
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 () ->
$"This is StaticProperty{i} on NestedType")
p
]
staticPropsInNestedType)
[nestedType])
Silinen sağlanmış türler hakkındaki ayrıntılar
Bu bölümdeki örnek yalnızca silinmiş sağlanan türleri sağlar ve aşağıdaki durumlarda özellikle yararlı olur:
Yalnızca veri ve yöntemleri içeren bir bilgi alanı için sağlayıcı yazarken.
Doğru çalışma zamanı türü semantiğinin, bilgi alanının pratik kullanımı açısından kritik olmadığı bir sağlayıcı yazarken.
Daha büyük bir bilgi alanı için bir sağlayıcı yazarken ve bilgi alanı için gerçek .NET türleri üretmek için teknik olarak uygun olmayan bir şekilde.
Bu örnekte, belirtilen her tür türü olarak silinir obj ve türün tüm kullanımları derlenmiş kodda tür olarak görünür obj . Aslında, bu örneklerdeki temeldeki nesneler dizelerdir, ancak tür System.Object .net derlenen kodda olduğu gibi görünecektir. ERASURE türünde tüm kullanımlar sayesinde, açık kutulamayı, kutudan çıkarma ve çıkarma türlerini alt alta yazmak için öğesini kullanabilirsiniz. Bu durumda, geçerli olmayan bir dönüştürme özel durumu, nesne kullanıldığında ortaya çıkabilir. Sağlayıcı çalışma zamanı, yanlış gösterimlerine karşı korumaya yardımcı olmak için kendi özel gösterim türünü tanımlayabilir. Silinen türleri F # içinde tanımlayamazsınız. Yalnızca sunulan türler silinebilir. Tür sağlayıcınız için silinen türler veya silinen türler sağlayan bir sağlayıcı kullanarak hem pratik hem de anlamsal olan sonuçları anlamanız gerekir. Silinen bir türün gerçek bir .NET türü yoktur. Bu nedenle, türü üzerinde doğru yansıma yapılamaz ve çalışma zamanı yayınlarını ve tam çalışma zamanı türü semantiğini kullanan diğer teknikleri kullanırsanız, silinen türleri alt dikey alabilirsiniz. Silinen türlerin alt sürümü sıklıkla çalışma zamanında tür atama özel durumlarına neden olur.
Silinen sağlanmış türler için gösterimler seçme
Silinen bazı türlerin kullanımları için hiçbir temsili gerekmez. Örneğin, silinen sağlanmış tür yalnızca statik özellikler ve Üyeler ve hiçbir Oluşturucu içerebilir; hiçbir yöntem veya özellik türün bir örneğini döndürmez. Silinen bir tür örneğe ulaşabilseniz, aşağıdaki soruları göz önünde bulundurmanız gerekir:
Bir belirtilen türün silinme nedir?
Bir belirtilen türün silinme türü derlenmiş .net kodunda nasıl görünür?
Belirtilen silinen bir sınıf türünün silinme her zaman türün devralma zincirindeki ilk silinmeyen temel türdür.
Belirtilen silinen bir arabirim türünün silinme her zaman olur
System.Object.
Belirtilen türde temsiller nelerdir?
- Silinmiş bir sağlanmış tür için olası nesneler kümesi, temsilleri olarak adlandırılır. Bu belgedeki örnekte, tüm silinen sağlanmış türlerin gösterimleri
Type1..Type100her zaman dize nesneleridir.
Bir belirtilen türün tüm temsilleri, belirtilen türün silinme ile uyumlu olmalıdır. (Aksi halde, F # derleyicisi tür sağlayıcısı kullanımı için bir hata verir veya geçerli olmayan doğrulanamayan .NET kodu oluşturulur. Bir tür sağlayıcısı geçerli olmayan bir temsili veren kodu döndürürse geçerli değildir.)
Aşağıdaki yaklaşımlardan birini kullanarak, sunulan nesneler için bir temsili seçebilirsiniz, her ikisi de çok yaygındır:
Yalnızca var olan bir .NET türü üzerinde kesin olarak belirlenmiş bir sarmalayıcı sağlıyorsanız, bu, genellikle bu türde silme, söz konusu türün örneklerini temsiller veya her ikisi için de anlamlı hale getirir. Bu yaklaşım, bu tür üzerindeki mevcut yöntemlerin büyük bir kısmının, kesin olarak belirlenmiş sürümü kullanırken hala anlamlı hale geldiğinde uygundur.
Var olan herhangi bir .NET API 'sinden önemli ölçüde farklı bir API oluşturmak istiyorsanız, belirtilen türler için tür ve gösterimler olacak çalışma zamanı türleri oluşturmak mantıklı olur.
Bu belgedeki örnek, dizeleri, belirtilen nesnelerin temsilleri olarak kullanır. Genellikle, diğer nesneleri temsiller için kullanmak uygun olabilir. Örneğin, bir sözlüğü özellik paketi olarak kullanabilirsiniz:
ProvidedConstructor(parameters = [],
invokeCode= (fun args -> <@@ (new Dictionary<string,obj>()) :> obj @@>))
Alternatif olarak, bir veya daha fazla çalışma zamanı işlemiyle birlikte gösterimi oluşturmak için çalışma zamanında kullanılacak tür sağlayıcınızda bir tür tanımlayabilirsiniz:
type DataObject() =
let data = Dictionary<string,obj>()
member x.RuntimeOperation() = data.Count
Daha sonra, belirtilen Üyeler bu nesne türünün örneklerini oluşturabilir:
ProvidedConstructor(parameters = [],
invokeCode= (fun args -> <@@ (new DataObject()) :> obj @@>))
Bu durumda, (isteğe bağlı olarak), bu türü oluştururken aşağıdaki gibi belirterek bu türü bir tür olarak kullanabilirsiniz baseType ProvidedTypeDefinition :
ProvidedTypeDefinition(…, baseType = Some typeof<DataObject> )
…
ProvidedConstructor(…, InvokeCode = (fun args -> <@@ new DataObject() @@>), …)
Temel dersler
Önceki bölümde, bir dizi türü, özelliği ve yöntemi sağlayan basit bir silme türü sağlayıcısı oluşturma konusu açıklanmaktadır. Bu bölümde ayrıca, bir tür sağlayıcısından silinen türler sağlamanın avantajları ve dezavantajları ve silinen türlerin açıklanabileceği avantajlar da dahil olmak üzere ERASURE türü kavramı açıklanmıştı.
Statik parametreleri kullanan bir tür sağlayıcısı
Statik veriler tarafından tür sağlayıcılarını Parametreleştirme özelliği, sağlayıcının herhangi bir yerel veya uzak veriye erişmesi gerekmeyen durumlarda bile çok sayıda ilginç senaryo sağlar. Bu bölümde, bir sağlayıcıyı bir araya getirmek için bazı temel tekniklerin öğrenirsiniz.
Denetlenen Regex sağlayıcısını yazın
Regexaşağıdaki derleme zamanı garantisi sağlayan bir arabirimdeki .net kitaplıklarını sarmalayan normal ifadeler için bir tür sağlayıcısı uygulamak istediğiniz Imagine:
Normal bir ifadenin geçerli olup olmadığı doğrulanıyor.
Normal ifadede herhangi bir grup adına dayalı eşleşmeler üzerinde adlandırılmış özellikler sağlama.
Bu bölümde, bu RegexTyped avantajları sağlamak üzere normal ifade deseninin parametreleştiren bir tür oluşturmak için tür sağlayıcılarının nasıl kullanılacağı gösterilmektedir. Sağlanan model geçerli değilse derleyici bir hata bildirir ve tür sağlayıcısı, eşleşmeler üzerinde adlandırılmış özellikler kullanarak erişebilmek için grupları düzeninden ayıklayabilir. Bir tür sağlayıcısı tasarladığınızda, sunulan API 'nin son kullanıcılara nasıl bakacağınızı ve bu tasarımın .NET koduna nasıl çevrileceğini göz önünde bulundurmanız gerekir. Aşağıdaki örnek, bu tür bir API 'nin, alan kodu bileşenlerini almak için 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 dönüştürdüğünde 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ü parametreli türü temsil eder
RegexTyped.RegexTypedOluşturucu, bir normal ifade oluşturucusuna çağrı ile sonuçlanır ve bu da, düzenin statik tür bağımsız değişkenini geçer.MatchYönteminin sonuçları standart tür ile temsil edilir Match .Her bir adlandırılmış Grup, belirtilen bir özellik ile sonuçlanır ve özelliğe erişilmesi, bir eşleşmenin koleksiyonunda bir dizin oluşturucunun kullanılmasına neden olur
Groups.
Aşağıdaki kod, bu tür bir sağlayıcıyı uygulayan mantığın çekirdekdir ve bu örnek, tüm üyelerin eklenmesi belirtilen türe atlar. Eklenen her üye hakkında daha fazla bilgi için bu konunun ilerleyen bölümlerindeki ilgili bölüme bakın.
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
patternve,optionsisteğe bağlı olan (varsayılan bir değer sağlandığı için).Statik bağımsız değişkenler sağlandığında, normal ifadenin bir örneğini oluşturursunuz. Bu örnek, Regex yanlış biçimlendirilmişse bir özel durum oluşturur ve bu hata kullanıcılara bildirilir.
DefineStaticParametersGeri çağırma içinde, bağımsız değişkenler sağlandıktan sonra döndürülecek türü tanımlarsınız.HideObjectMethodsIntelliSense deneyiminin kolaylaştırmaya devam edebilmesi için bu kod doğru olarak ayarlanır. Bu öznitelik,,Equals,GetHashCodeFinalizeve üyelerinin,GetTypebelirtilen bir nesne için IntelliSense listelerinden gizlenmesine neden olur.objYöntemin temel türü olarak kullanırsınız, ancak birRegexsonraki örnekte gösterildiği gibi bu türün çalışma zamanı temsili olarak bir nesnesi kullanırsınız.Bir
Regexnormal ifade geçerli olmadığında oluşturucuya yapılan çağrı bir oluşturur ArgumentException . derleyici bu özel durumu yakalar ve derleme zamanında veya Visual Studio düzenleyicisinde kullanıcıya bir hata mesajı bildirir. Bu özel durum, normal ifadelerin bir uygulama çalıştırmadan doğrulanmasını sağlar.
Yukarıda tanımlanan tür hiçbir anlamlı Yöntem veya özellik içermediğinden henüz yararlı değildir. İlk olarak, statik bir IsMatch Yöntem ekleyin:
let isMatch =
ProvidedMethod(
methodName = "IsMatch",
parameters = [ProvidedParameter("input", typeof<string>)],
returnType = typeof<bool>,
isStatic = 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 IsMatch , girdi olarak bir dize alan ve döndüren bir yöntemi tanımlar bool . Tek karmaşık bölüm, args tanım içindeki bağımsız değişkenin kullanımı InvokeCode . Bu örnekte, args Bu yöntemin bağımsız değişkenlerini temsil eden tekliflerin bir listesidir. Yöntem bir örnek yöntemi ise, ilk bağımsız değişken bağımsız değişkenini temsil eder this . Ancak, bir statik yöntem için bağımsız değişkenler yalnızca yöntemin açık bağımsız değişkenlerinden biridir. Alıntılanmış değerin türünün belirtilen dönüş türüyle (Bu durumda) eşleşmesi gerektiğini unutmayın bool . Ayrıca, bu kodun, AddXmlDoc IntelliSense aracılığıyla sağlayabilmeniz için, sunulan yöntemin de yararlı belgeler içerdiğinden emin olmak için yöntemini kullandığını unutmayın.
Sonra bir örnek eşleşme yöntemi ekleyin. Ancak, bu yöntem, Match grupların kesin olarak belirlenmiş bir biçimde erişilebilmesi için, belirtilen türde bir değer döndürmelidir. Bu nedenle, önce türü bildirirsiniz Match . Bu tür statik bir bağımsız değişken olarak sağlanan modele bağlı olduğundan, bu tür parametreli 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 eşleşme türüne bir özellik eklersiniz. Çalışma zamanında, bir eşleşme değer olarak temsil edilir Match . bu nedenle, özelliği tanımlayan teklifin Groups ilgili grubu almak için dizinlenmiş özelliği kullanması gerekir.
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($"""Gets the ""{group}"" group from this match""")
matchTy.AddMember prop
Yine, XML belgelerini verilen özelliğe eklebileceğinizi unutmayın. Ayrıca, bir işlev sağlanırsa özelliğin okuna ve bir işlev sağlanıyorsa özelliğin yazıldığına, bu nedenle elde edilen özelliğin salt okunur GetterCode SetterCode olduğunu unutmayın.
Artık bu tür bir değer döndüren bir örnek yöntemi Match 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ştururken yöntemin çağrıldı olduğu örneği temsil eder ve giriş args[0] RegexTyped bağımsız args[1] değişkenidir.
Son olarak, sağlanan türün örneklerinin oluşturulamalarını sağlamak için bir oluşturucu sağlar.
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 bir .NET Regex örneği oluşturma işlemiyle silinir. Bu örnek, sağlanan türün silinmesi nedeniyle yeniden bir nesnesine obj kutulanmıştır. Bu değişiklikle, konu başlığında daha önce belirtilen örnek API kullanımı beklendiği gibi çalışır. Aşağıdaki kod eksiksiz 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>,
isStatic = 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 occurrence 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 ()
Önemli Dersler
Bu bölümde, statik parametreleri üzerinde çalışan bir tür sağlayıcısı oluşturma açıklanmıştır. Sağlayıcı statik parametreyi denetler ve değerine göre işlemler sağlar.
Yerel veriler tarafından desteklene bir tür sağlayıcısı
Sık sık tür sağlayıcılarının API'leri yalnızca statik parametrelere değil, yerel veya uzak sistemlerden gelen bilgilere de göre sunmalarını istiyor olabilirsiniz. Bu bölümde yerel veri dosyaları gibi yerel verileri temel alan tür sağlayıcıları ele almaktadır.
Basit CSV Dosya Sağlayıcısı
Basit bir örnek olarak, bilimsel verilere Virgülle Ayrılmış Değer (CSV) biçiminde erişmek için bir tür sağlayıcısı düşünün. Bu bölümde, aşağıdaki tabloda gösterildiği gibi CSV dosyalarının bir üst bilgi satırı ve ardından kayan nokta verileri içerdiği varsayılarak:
| Uzaklık (ölçüm) | Saat (saniye) |
|---|---|
| 50.0 | 3.7 |
| 100.0 | 5.2 |
| 150.0 | 6.4 |
Bu bölümde, türünde bir özelliği ve türünde bir özelliği olan satırları almak için kullanabileceğiniz bir Distance float<meter> türün Time nasıl sağ olduğu float<second> gösterir. Kolaylık olması için aşağıdaki varsayımlar yapılır:
Üst bilgi adları birim olmayan veya "Ad (birim)" şeklindedir ve virgül içermez.
Birimler, FSharp.Data.UnitSystems.SI.UnitNames Modülü (F#) modülünün tanımladığı tüm System International (SI) birimleridir.
Birimlerin hepsi bileşik (ölçüm/saniye gibi) yerine basittir (ölçüm gibi).
Tüm sütunlar kayan nokta verileri içerir.
Daha eksiksiz bir sağlayıcı bu kısıtlamaları gevşetir.
Yine ilk adım API'nin nasıl olması gerektiğini düşünmektir. Önceki tablonun içeriğine (virgülle ayrılmış biçimde) sahip bir dosya verilebilirse, sağlayıcı kullanıcıları aşağıdaki örnekteki gibi bir info.csv kod yazabilir:
let info = new MiniCsv<"info.csv">()
for row in info.Data do
let time = row.Time
printfn $"{float time}"
Bu durumda, derleyici bu çağrıları aşağıdaki örnekteki gibi bir şeye dönüştürmeli:
let info = new CsvFile("info.csv")
for row in info.Data do
let (time:float) = row[1]
printfn $"%f{float time}"
En uygun çeviri, tür sağlayıcısının tür sağlayıcısının CsvFile derlemesinde gerçek bir tür tanımlaması gerektirir. Tür sağlayıcıları önemli mantığı sarmak için genellikle birkaç yardımcı türü ve yöntemi kullanır. Ölçüler çalışma zamanında silindi, bir satırın float[] silinmiş türü olarak kullanabilirsiniz. Derleyici farklı sütunları farklı ölçü türlerine sahip olarak davranır. Örneğin, örneğimizde ilk sütun türünde, ikinci sütunda float<meter> ise float<second> türündedir. Ancak, silinmiş gösterim oldukça basit kalarak devam ediyor olabilir.
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 ->
line.Split(',') |> Array.map float
}
|> Seq.cache
member _.Data = data
[<TypeProvider>]
type public MiniCsvProvider(cfg:TypeProviderConfig) as this =
inherit TypeProviderForNamespaces(cfg)
// 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 run time.
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 noktalara dikkatin:
Aşırı yüklenmiş oluşturucular özgün dosyanın veya aynı şemaya sahip bir dosyanın okunmalarına izin verir. Bu düzen, yerel veya uzak veri kaynakları için bir tür sağlayıcısı yazarak yaygındır ve bu düzen, yerel bir dosyanın uzak veriler için şablon olarak kullanılmaktadır.
Göreli dosya adlarını çözümlemek için tür sağlayıcısı oluşturucuya geçirilen TypeProviderConfig değerini kullanabilirsiniz.
Sağlanan özelliklerin
AddDefinitionLocationkonumunu tanımlamak için yöntemini kullanabilirsiniz. Bu nedenle, sağlananGo To Definitionbir özellikte kullanırsanız, CSV dosyası Visual Studio.SI birimlerini
ProvidedMeasureBuilderarama ve ilgili türleri oluşturmak için türünüfloat<_>kullanabilirsiniz.
Önemli Dersler
Bu bölümde, veri kaynağının kendisinde yer alan basit bir şema ile yerel bir veri kaynağı için tür sağlayıcısı oluşturma açıklanmıştır.
Devam
Aşağıdaki bölümlerde daha fazla çalışma için öneriler yer alınmıştır.
Silinen Türler için Derlenmiş Koda Bakış
Tür sağlayıcısının kullanımının yayılan koda nasıl karşılık olduğu hakkında fikir vermek için, bu konuda daha önce kullanılan işlevini kullanarak aşağıdaki HelloWorldTypeProvider işleve bakın.
let function1 () =
let obj1 = Samples.HelloWorldTypeProvider.Type1("some data")
obj1.InstanceProperty
Aşağıdaki görüntüde, ildasm.exe kullanılarak elde edilen kodun koda ildasm.exe:
.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
Örnekte de olduğu gibi, tür ve özelliğin tüm bahsetmeleri silindi ve yalnızca ilgili Type1 InstanceProperty çalışma zamanı türlerinde işlemler bırakıldı.
Tü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özlemler.
Bağlantı Protokolleri Için Sağlayıcılar Genel olarak, veri ve hizmet bağlantısı protokolleri için OData veya SQL sağlayıcı URL'lerinin adları veya ile TypeProvider TypeProviders bitmeli. Örneğin, aşağıdaki dizeye benzer bir DLL adı kullanın:
Fabrikam.Management.BasicTypeProviders.dll
Sağlanan türlerinizi ilgili ad alanının üyesi olduğundan emin olun ve gerçekleştirilen bağlantı protokolünü işaret edin:
Fabrikam.Management.BasicTypeProviders.WmiConnection<…>
Fabrikam.Management.BasicTypeProviders.DataProtocolConnection<…>
Genel Kodlama için Yardımcı Program Sağlayıcıları. Normal ifadelerde olduğu gibi bir yardımcı program türü sağlayıcısı için, tür sağlayıcısı aşağıdaki örnekte de olduğu 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 ayrılmış veri kaynağına bağlanarak yalnızca veri sağlar. Bu durumda, soneki bırakmalı TypeProvider ve .NET adlandırması için normal kuralları kullan gerekir:
#r "Fabrikam.Data.Freebase.dll"
let data = Fabrikam.Data.Freebase.Astronomy.Asteroids
Daha fazla bilgi için bu GetConnection konunun devamlarında açıklanan tasarım kuralına bakın.
Tür Sağlayıcıları için Tasarım Desenleri
Aşağıdaki bölümlerde, tür sağlayıcıları yazmada kullanabileceğiniz tasarım desenleri açıklanmaktadır.
GetConnection Tasarım Düzeni
Çoğu tür sağlayıcısı, aşağıdaki örnekte de olduğu gibi, FSharp.Data.TypeProviders.dll sağlayıcılar tarafından kullanılan GetConnection deseni kullanmak üzere yaz kullanılmalıdır:
#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
Uzak Veri ve Hizmetler Tarafından Desteklene Tür Sağlayıcıları
Uzak veri ve hizmetler tarafından desteklene bir tür sağlayıcısı oluşturmadan önce, bağlı programlamada doğal olan bir dizi sorunu göz önünde bulundurabilirsiniz. Bu sorunlar aşağıdaki konuları içerir:
şema eşleme
şema değişikliğinin varlığında canlılık ve geçersizlik
şema önbelleğe alma
veri erişim işlemlerinin zaman uyumsuz uygulamaları
LINQ sorguları da dahil olmak üzere sorguları destekleme
kimlik bilgileri ve kimlik doğrulaması
Bu konu, bu sorunları daha fazla incelemez.
Ek Yazma Teknikleri
Kendi tür sağlayıcılarınızı yazarken aşağıdaki ek teknikleri kullanmak iyi olabilir.
Talep Üzerine Türler ve Üyeler Oluşturma
ProvidedType API'sinde AddMember'ın gecikmeli sürümleri vardır.
type ProvidedType =
member AddMemberDelayed : (unit -> MemberInfo) -> unit
member AddMembersDelayed : (unit -> MemberInfo list) -> unit
Bu sürümler, isteğe bağlı tür alanları oluşturmak için kullanılır.
Dizi türleri ve Genel Tür Örnek sağlama
Normal , ve dahil olmak üzere herhangi bir örneğinde kullanarak sağlanan üyeleri (imzaları dizi türlerini, byref türlerini ve genel türlerin örneklerini içerir) MakeArrayType MakePointerType MakeGenericType Type ProvidedTypeDefinitions sağlarsanız.
Not
Bazı durumlarda içinde yardımcıyı kullanmak zorunda ProvidedTypeBuilder.MakeGenericType olabilir. Diğer ayrıntılar için Tür Sağlayıcısı SDK belgelerine bakın.
Ölçü Birimi Ek Açıklamalarını Sağlama
ProvidedTypes API'si, ölçü ek açıklamaları sağlamak için yardımcılar sağlar. Örneğin, türünü sağlamak float<kg> 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])
türünü sağlamak Nullable<decimal<kg/m^2>> 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 |]
Project-Local veya Script-Local Erişme
Bir tür sağlayıcısının her örneğine, yapı sırasında TypeProviderConfig bir değer verilebilir. Bu değer sağlayıcı için "çözümleme klasörünü" (derlemenin proje klasörünü veya bir betiği içeren dizini), başvurulan derlemelerin listesini ve diğer bilgileri içerir.
Örneğin
Sağlayıcılar, F# dil hizmetine şema varsayımlarını değiştirmiş olduğunu bildirmek için geçersiz kılınma sinyallerine neden olabilir. Geçersiz kılınma oluştuğunda, sağlayıcı Visual Studio' içinde barındırıyorsa, bir tür denetimi Visual Studio. Sağlayıcı F# Etkileşimli veya F# Derleyicisi (fsc.exe) tarafından barındırılırken bu sinyal yoksayılır.
Önbelleğe Alma Şema Bilgileri
Sağlayıcıların genellikle şema bilgilerine erişimi önbelleğe almak zorunda olması gerekir. Önbelleğe alınan veriler, statik parametre olarak veya kullanıcı verileri olarak verilen bir dosya adı kullanılarak depolanmış olmalıdır. Şema önbelleğe alma örneği, LocalSchemaFile derlemede tür sağlayıcılarında FSharp.Data.TypeProviders parametresidir. Bu sağlayıcıların uygulanmasında, bu statik parametre tür sağlayıcısını ağ üzerinden veri kaynağına erişmek yerine belirtilen yerel dosyada şema bilgilerini kullanmaya yönlendirmektedir. Önbelleğe alınmış şema bilgilerini kullanmak için statik parametresini de olarak ForceUpdate ayarlay false gerekir. Çevrimiçi ve çevrimdışı veri erişimini etkinleştirmek için benzer bir teknik kullanabilirsiniz.
Backing Assembly
Bir veya dosyasını derlerken, oluşturulan .dll için backing dosya, sonuçta elde edilen .dll .exe derlemeye statik olarak bağlıdır. Bu bağlantı, Ara Dil (IL) türü tanımları ve tüm yönetilen kaynaklar yedek derlemeden son derlemeye kopyalayıp oluşturulur. Bir F# Etkileşimli, .dll dosya kopyalanmaz ve bunun yerine doğrudan F# Etkileşimli yüklenir.
Tür Sağlayıcılarından Özel Durumlar ve Tanılamalar
Sağlanan türlerden tüm üyelerin tüm kullanımları özel durumlar oluşturur. Her durumda, bir tür sağlayıcısı bir özel durum oluşturursa, konak derleyici hatayı belirli bir tür sağlayıcısına öznitelikler.
Tür sağlayıcısı özel durumları hiçbir zaman iç derleyici hatalarına neden olmayacaktır.
Tür sağlayıcıları uyarıları raporlayamıyor.
Bir tür sağlayıcısı F# derleyicisinde, F# geliştirme ortamında veya F# Etkileşimli sağlayıcının tüm özel durumları yakalanıyor. Message özelliği her zaman hata metnidir ve yığın izlemesi yoktur. Bir özel durum oluşturursanız şu örnekleri atsanız:
System.NotSupportedException,System.IO.IOException,System.Exception.
Oluşturulan Türleri Sağlama
Bu belgede şimdiye kadar silinmiş türlerin nasıl sağlanmıştır? Kullanıcıların programına gerçek .NET tür tanımları olarak eklenen oluşturulan türleri sağlamak için F# içinde tür sağlayıcısı mekanizmasını da kullanabilirsiniz. Bir tür tanımı kullanarak oluşturulan sağlanan türlere başvursanız gerekir.
open Microsoft.FSharp.TypeProviders
type Service = ODataService<"http://services.odata.org/Northwind/Northwind.svc/">
F# 3.0 yayınlarının parçası olan ProvidedTypes-0.2 yardımcı kodu, oluşturulan türleri sağlamak için yalnızca sınırlı destek içerir. Oluşturulan tür tanımı için aşağıdaki deyimlerin true olması gerekir:
isErasedolarak ayarfalsegerekir.Oluşturulan tür, oluşturulan kod parçaları için bir kapsayıcıyı
ProvidedAssembly()temsil eden yeni oluşturulan bir türüne eklenmiştir.Sağlayıcının, diskte eşleşen bir .NET .dll dosyası olan bir .dll derlemesi olmalıdır.
Kurallar ve Sınırlamalar
Tür sağlayıcılarını yazarken, aşağıdaki kuralları ve sınırlamaları göz içinde bulundurabilirsiniz.
Sağlanan türlere ulaşılabilir olması gerekir
Sağlanan tüm türlere iç içe olmayan türlerden erişilebilir olması gerekir. İç içe olmayan türler oluşturucuya yapılan çağrıda TypeProviderForNamespaces veya çağrısında AddNamespace verilir. Örneğin, sağlayıcı bir türü sağlarsa, T'nin iç içe olmayan bir tür olduğundan veya bir türün altında StaticClass.P : T iç içe geçmiş olduğundan emin olun.
Örneğin, bazı sağlayıcılar bu türleri içeren gibi DataTypes statik bir T1, T2, T3, ... sınıfa sahip olur. Aksi takdirde hata, A derlemesinde T türüne başvuru bulunsa da türün o derlemede buluna olmadığını söylüyor. Bu hata görüntülenirse, tüm alt türlerinize sağlayıcı türlerinden ulaşılaa olduğunu doğrulayın. Not: T1, T2, T3... Bu türler, uçta olan türler olarak adlandırılır. Bunları erişilebilir bir ad alanına veya üst türe koymayı unutmayın.
Tür Sağlayıcısı Mekanizmasının Sınırlamaları
F# içinde tür sağlayıcısı mekanizması aşağıdaki sınırlamalara sahiptir:
F# içinde tür sağlayıcıları için temel alınan altyapı, sağlanan genel türleri veya sağlanan genel yöntemleri desteklemez.
Mekanizma, statik parametrelerle iç içe türleri desteklemez.
Geliştirme İpuçları
Geliştirme sürecinde aşağıdaki ipuçları yararlı olabilir:
İki örnek Visual Studio
Tür sağlayıcısını bir örnekte geliştirebilir ve sağlayıcıyı diğer örnekte test etmek için test IDE'sini .dll sağlayıcının yeniden oluşturulmuş olması önleyen bir kilit alır. Bu nedenle, sağlayıcı ilk örnekte Visual Studio ikinci örneğini kapatmanız ve sağlayıcıyı 2. örneği yeniden açmanız gerekir.
fsc.exe çağırmalarını kullanarak tür sağlayıcılarının fsc.exe
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# Etkileşimli derleyici)
devenv.exe (Visual Studio)
Bir test betiği dosyasında (örneğin, script.fsxfsc.exe kullanarak tür sağlayıcılarının hatasını kolayca ayıklayabilirsiniz. Hata ayıklayıcıyı komut isteminden başlatabilirsiniz.
devenv /debugexe fsc.exe script.fsx
Print-to-stdout günlük kaydını kullanabilirsiniz.