Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
F# dilindeki tür sağlayıcısı mekanizması, bilgi zengin programlama desteğinin önemli bir parçası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şturacağınız açıklanmaktadır. F# dilindeki 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 oluşturucu tür sağlayıcısı içerir.
FSharp.Data.SqlClient, T-SQL'in F# diline derleme zamanında denetimli olarak katıştırılması için bir tür sağlayıcıları kümesine sahiptir.
Ö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şunuzun her biri kendi kararlı veri şemasına sahip çok sayıda ve artan sayıda adlandırılmış veri kümesi sağlayan bir veri hizmeti olabilir. Şemaları okuyan ve geçerli veri kümelerini programcıya güçlü bir şekilde türlendirilmiş olarak sunan bir tür sağlayıcı oluşturabilirsiniz.
Başlamadan Önce
Tür sağlayıcısı mekanizması öncelikle F# programlama deneyimine kararlı veri ve hizmet bilgileri alanları eklemek için tasarlanmıştır.
Bu mekanizma, program yürütme sırasında şemaları program mantığına uygun şekilde değişen bilgi alanları eklemek için tasarlanmamıştır. Ayrıca bu etki alanı bazı geçerli kullanımlar içerse bile mekanizma dil içi meta programlama için tasarlanmamıştır. Bu mekanizmayı yalnızca gerekli yerlerde ve bir tür sağlayıcısının geliştirilmesinin çok yüksek değere sahip olduğu durumlarda kullanmanız gerekir.
Şemanın mevcut olmadığı durumlarda bir tür sağlayıcısı yazmaktan kaçınmalısınız. Benzer şekilde, sıradan bir .NET kitaplığının (hatta mevcut bir kitaplığın) yeterli olacağı 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ı? Öyleyse, F# ve .NET tür sistemine nasıl bir eşleme yapılıyor?
Uygulamanız için başlangıç noktası olarak mevcut (dinamik olarak yazılan) bir API kullanabilir misiniz?
Siz ve kuruluşunuz, yazmaya değer hale getirmek için tür sağlayıcısını yeterince kullanıyor musunuz? Normal bir .NET kitaplığı gereksinimlerinizi 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ütme sırasında değişecek mi?
Tür sağlayıcıları, şemanın çalışma zamanında ve derlenmiş kodun ömrü boyunca kararlı olduğu durumlar için en uygun olanıdır.
Basit Tip Sağlayıcısı
Bu örnek Samples.HelloWorldTypeProvider örneğidir ve examples dizinindeki örneklere benzer. Sağlayıcı, F# söz dizimi imzası kullanılarak ve Type1 dışındaki tüm ayrıntıları atlayarak aşağıda gösterilen kodda 100 silinmiş tür içeren bir "tür alanı" sağlar. Silinen türler hakkında daha fazla bilgi için, bu konunun devamı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ümesinin statik olarak bilindiğini unutmayın. Bu örnek, sağlayıcıların şemaya bağlı türler sağlama özelliğinden yararlanmaz. Tür sağlayıcısının uygulanması aşağıdaki kodda özetlenmiştir ve ayrıntılar bu konunun sonraki bölümlerinde ele alınmış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 ayrı bir Visual Studio örneği açın, bir F# betiği oluşturun ve ardından aşağıdaki kodda gösterildiğ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, tür sağlayıcısının Samples.HelloWorldTypeProvider oluşturduğu ad alanı altında türleri arayın.
Sağlayıcıyı yeniden derlemeden önce, sağlayıcı DLL'sini kullanan tüm Visual Studio ve F# Interactive örneklerini kapattığınızdan emin olun. Aksi takdirde, çıkış DLL'i kilitlendiğinden derleme hatası oluşur.
Print ifadelerini kullanarak bu sağlayıcıda hata ayıklamak için, sağlayıcıda bir sorun gösteren bir betik oluşturun 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, yönetici kimlik bilgileriyle Visual Studio için Geliştirici Komut İstemi'ni 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, Hata Ayıkla menüsünü açın, Debug/Attach to process… öğesini seçin ve betiğinizi düzenlediğiniz başka bir devenv işleme ekleyin. Bu yöntemi kullanarak, ikinci örneğe etkileşimli olarak ifadeler yazarak (tam IntelliSense ve diğer özelliklerle) tür sağlayıcısındaki belirli mantığı daha kolay hedefleyebilirsiniz.
Oluşturulan koddaki hataları daha iyi tanımlamak için Yalnızca Kodum hata ayıklamasını devre dışı bırakabilirsiniz. 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, Debug menüsünü açarak ardından Exceptions seçeneğini seçebilir veya Ctrl+Alt+E tuşlarına basarak Exceptions iletişim kutusunu açıp ilk şans özel durum yakalamayı ayarlayabilirsiniz. Bu iletişim kutusunda, Common Language Runtime Exceptions altında Thrown onay 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 asıl bölümlerinde size yol gösterir. İlk olarak, özel tür sağlayıcısının türünü tanımlarsınız:
[<TypeProvider>]
type SampleTypeProvider(config: TypeProviderConfig) as this =
Bu tür genel olmalıdır ve ayrı bir F# projesi türü içeren derlemeye başvurduğunda derleyicinin tür sağlayıcısını tanıması için bunu TypeProvider özniteliğiyle işaretlemeniz gerekir. Yapılandırma parametresi isteğe bağlıdır ve varsa F# derleyicisinin 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 uygulayacaksınız. Bu durumda, API'deki TypeProviderForNamespaces türünü temel tür olarak kullanırsınızProvidedTypes. Bu yardımcı tür, her biri doğrudan sınırlı sayıda sabit ve özenle sağlanmış türü içeren, özenle sağlanmış ad alanlarından oluşan sınırlı bir koleksiyon sağlayabilir. Bu bağlamda sağlayıcı, gerekli olmasalar veya kullanılmasalar bile türleri hevesle oluşturur.
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ı derlemesinin kendisini bulun. Bu derleme daha sonra, verilen silinmiş türlerin mantıksal üst tipi olarak kullanılır.
let namespaceName = "Samples.HelloWorldTypeProvider"
let thisAssembly = Assembly.GetExecutingAssembly()
Ardından, Tür1'den Tür100'e kadar her bir türü sağlamak için bir işlev oluşturun. Bu işlev, bu konunun ilerleyen bölümlerinde daha ayrıntılı olarak açıklanmıştır.
let makeOneProvidedType (n:int) = …
Ardından sağlanan 100 türü oluşturun:
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, tür sağlayıcısı DLL'sini oluşturduğunuzu belirten bir derleme özniteliği ekleyin:
[<assembly:TypeProviderAssembly>]
do()
Bir tür ve üyelerini sunmak
makeOneProvidedType işlevi, türlerden birini sağlamanın gerçek işini yapar.
let makeOneProvidedType (n:int) =
…
Bu adımda bu işlevin uygulanması açıklanmaktadır. İlk olarak, sağlanan türü oluşturun (örneğin, n = 1 olduğunda Tür1 veya n = 57 olduğunda 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 noktaları not edin:
Bu sağlanan tür silinir. Temel türün olduğunu
objbelirttiğinizden, örnekler derlenmiş kodda obj türünde değerler 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ı derlemesinin kendisi olmalıdır.
Ardından türüne XML belgeleri ekleyin. Bu dokümantasyon gecikir, yani konak derleyici ihtiyaç duyarsa gerektiğinde hesaplanır.
t.AddXmlDocDelayed (fun () -> $"""This provided type {"Type" + string n}""")
Ardından türüne sağlanan bir statik özellik eklersiniz:
let staticProp = ProvidedProperty(propertyName = "StaticProperty",
propertyType = typeof<string>,
isStatic = true,
getterCode = (fun args -> <@@ "Hello!" @@>))
Bu özelliği almak her zaman "Hello!" dizesini değerlendirir.
GetterCode özelliği, konak derleyicisinin özelliği almak için oluşturduğu kodu temsil eden bir F# teklifi kullanır. Teklifler hakkında daha fazla bilgi için bkz. Kod Teklifleri (F#).
Özelliğe XML belgelendirmesi ekleyin.
staticProp.AddXmlDocDelayed(fun () -> "This is a static property")
Şimdi sağlanan özelliği sağlanan türe ekleyin. Sağlanan bir üyeyi tek ve tek bir türe eklemeniz gerekir. Aksi takdirde üyeye hiçbir zaman erişilemez.
t.AddMember staticProp
Şimdi parametre içermeyen sağlanan bir oluşturucu oluşturun.
let ctor = ProvidedConstructor(parameters = [ ],
invokeCode = (fun args -> <@@ "The object data" :> obj @@>))
Oluşturucu InvokeCode, konak derleyicisinin oluşturucu çağrıldığında oluşturduğu 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, temel veriler "Nesne verileri" kullanılarak oluşturulacaktır. Alıntılanan kod, bu türün verilen tür olarak tanımlandığında belirttiğiniz gibi, bu sağlanan türün tür silinmesi olduğu için obj'ye bir dönüştürme içermektedir.
Oluşturucuya XML belgeleri 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 @@>))
InvokeCode oluşturucu için yeniden bir F# alıntısı döndürür, bu da konak derleyicinin yönteme yaptığı çağrının kodunu temsil eder. Örneğin, aşağıdaki oluşturucuyu kullanabilirsiniz:
new Type10("ten")
Sağlanan türün bir örneği, altında yatan veri "on" ile oluşturulur. Fonksiyonun InvokeCode bir alıntı döndürdüğünü fark etmiş olabilirsiniz. Bu işlevin girişi, oluşturucu parametresi başına bir ifade listesidir. Bu durumda, içinde tek parametre değerini temsil eden bir ifade kullanılabilir args[0]. Oluşturucuya yapılan bir çağrının kodu, dönen değeri silinen türe dönüştürürobj. Sağlanan ikinci oluşturucuyu türüne ekledikten sonra, sağlanan bir ö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 nesnesi olan dizenin uzunluğunu döndürür. Özellik, GetterCode konak derleyicinin bu özelliği elde etmek için oluşturduğu kodu belirten bir F# alıntısı döndürür.
InvokeCode gibi, GetterCode işlevi bir alıntı döndürür. Konak 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 getter'ın çağrıldığı örneği temsil eden tek bir ifadeyi içerir ve bu ifadeye args[0] kullanarak erişebilirsiniz. uygulama GetterCode , silinen türdeki obj sonuç alıntısına eklenir ve derleyicinin nesnenin bir dize olduğunu denetleme mekanizmasını karşılamak için bir tür dönüştürme kullanılır. öğesinin makeOneProvidedType sonraki bölümünde tek parametreli bir örnek yöntemi sağlanır.
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çeren iç içe bir tür oluşturun. Bu iç içe türün ve özelliklerinin oluşturulması gecikir, yani 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])
Kaldırılan Sağlanan Türlerin detayları
Bu bölümdeki örnek, yalnızca aşağıdaki durumlarda özellikle yararlı olan silinmiş sağlanan türleri sağlar:
Yalnızca veri ve metotları içeren bir bilgi alanı için sağlayıcı yazarken.
Bilgi alanının pratik kullanımı için doğru çalışma zamanı türü semantiğin kritik olmadığı bir sağlayıcı yazarken.
Çok büyük ve birbirine bağlı bir bilgi alanı için bir sağlayıcı yazarken, bilgi alanı için gerçek .NET türleri oluşturmak teknik olarak uygun değildir.
Bu örnekte, verilen her tür obj şeklinde silinir ve türün tüm kullanımları derlenmiş kodda obj türü olarak görünür. Aslında, bu örneklerde temel alınan nesneler dizelerdir, ancak tür .NET derlenmiş kodunda olduğu gibi System.Object görünür. Tür silme işlemlerinin tüm kullanımlarında olduğu gibi, silinen türleri alt etmek için açık kutulama, kutudan çıkarma ve dönüştürme işlemlerini kullanabilirsiniz. Bu durumda, nesne kullanıldığında geçersiz bir dönüşüm istisnası oluşabilir. Bir sağlayıcı çalışma zamanı, yanlış gösterimlere 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 sağlanan türler silinebilir. Silinen türleri tür sağlayıcınız için doğrudan kullanmanın veya silinen türler sağlayan bir sağlayıcı kullanmanın, hem pratik hem de semantik sonuçlarını anlamanız gerekir. Silinmiş bir türün gerçek bir .NET türü yoktur. Bu nedenle, tür üzerinde doğru yansıma yapamazsınız ve tam çalışma zamanı türü semantiği kullanan çalışma zamanı atamaları ve diğer teknikleri kullanırsanız silinen türleri alta çevirebilirsiniz. Silinen türlerin alt sürüme çevrilmesi genellikle çalışma zamanında tür atama özel durumlarına neden olur.
Silinen Sağlanan Türler için Gösterim seçme
Silinen sağlanan türlerin bazı kullanımları için gösterim gerekmez. Örneğin, silinen sağlanan tür yalnızca statik özellikler ve üyeler içerebilir ve oluşturucu içermeyebilir ve hiçbir yöntem veya özellik türün bir örneğini döndürmez. Silinmiş olan bir türün örneklerine ulaşabiliyorsanız, aşağıdaki soruları göz önünde bulundurmanız gerekir:
Verilen bir türün silinmesi nedir?
Sağlanan türün silinmesi, türün derlenmiş .NET kodunda nasıl göründüğüdür.
Sağlanan bir silinmiş sınıf türünün silinmesi, her zaman türün devralma zincirinde yer alan ilk silinmemiş temel türdür.
Sağlanan bir silinen arabirim türünün silinmesi her zaman
System.Objectşeklindedir.
Sağlanan türün gösterimleri nelerdir?
- Silinmiş sağlanan bir tür için olası nesneler kümesine temsiller denir. Bu belgedeki örnekte, silinen tüm türlerin
Type1..Type100gösterimleri her zaman dize nesneleridir.
Sağlanan türün tüm gösterimleri, sağlanan türün silinmesiyle uyumlu olmalıdır. (Aksi takdirde, F# derleyicisi tür sağlayıcısının kullanımı için bir hata verir veya geçerli olmayan doğrulanamaz .NET kodu oluşturulur. Tür sağlayıcısı geçerli olmayan bir gösterim veren kod döndürüyorsa geçerli değildir.)
Sağlanan nesneler için, her ikisi de çok yaygın olan aşağıdaki yaklaşımlardan birini kullanarak bir gösterim seçebilirsiniz:
Var olan bir .NET türü üzerinde sıkı yazılmış bir sarmalayıcı sağlıyorsanız, genellikle türünüzün bu türe değişen, bu tür örneklerini gösterim olarak kullanan veya her ikisini birden yapan bir yapıya sahip olması mantıklıdır. Bu yaklaşım, bu türdeki mevcut yöntemlerin çoğunun, güçlü türlendirilmiş sürüm kullanıldığında hala anlamlı olduğu durumlarda uygundur.
Mevcut .NET API'lerinden önemli ölçüde farklı bir API oluşturmak istiyorsanız, sağlanan türlerin tür silme işlemlerini ve temsillerini içerecek çalışma zamanı türlerini oluşturmak mantıklıdır.
Bu belgedeki örnek, sağlanan nesnelerin gösterimleri olarak dizeleri kullanır. Sıklıkla, gösterimler için diğer nesneleri kullanmak uygun olabilir. Örneğin, bir sözlüğü özellikler torbası olarak kullanabilirsiniz.
ProvidedConstructor(parameters = [],
invokeCode= (fun args -> <@@ (new Dictionary<string,obj>()) :> obj @@>))
Alternatif olarak, tür sağlayıcınızda bir veya daha fazla çalışma zamanı işlemiyle birlikte gösterimi oluşturmak için çalışma zamanında kullanılacak bir tür tanımlayabilirsiniz:
type DataObject() =
let data = Dictionary<string,obj>()
member x.RuntimeOperation() = data.Count
Sağlanan üyeler bu nesne türünün örneklerini oluşturabilir:
ProvidedConstructor(parameters = [],
invokeCode= (fun args -> <@@ (new DataObject()) :> obj @@>))
Bu durumda, bu türü oluştururken baseTypeolarak belirterek (isteğe bağlı olarak) bu türü tür silme olarak ProvidedTypeDefinition kullanabilirsiniz:
ProvidedTypeDefinition(…, baseType = Some typeof<DataObject> )
…
ProvidedConstructor(…, InvokeCode = (fun args -> <@@ new DataObject() @@>), …)
Önemli Dersler
Önceki bölümde, bir dizi tür, özellik ve yöntem sağlayan basit bir silme türü sağlayıcısının nasıl oluşturulacağı açıklanmıştır. Bu bölümde, bir tür sağlayıcısından silinen türleri sağlamanın bazı avantajları ve dezavantajları da dahil olmak üzere tür silme kavramı açıklanmış ve silinen türlerin gösterimleri ele alınmıştır.
Statik Parametreler Kullanan Bir Tür Sağlayıcısı
Tür sağlayıcılarını statik verilere göre parametreleştirebilme özelliği, sağlayıcının herhangi bir yerel veya uzak veriye erişmesi gerekmese bile birçok ilginç senaryoya olanak tanır. Bu bölümde, böyle bir sağlayıcıyı bir araya getirmek için bazı temel teknikleri öğreneceksiniz.
Tür İşaretli Regex Sağlayıcısı
.NET Regex kitaplıklarını aşağıdaki derleme zamanı garantilerini sağlayan bir arabirimde sarmalayan normal ifadeler için bir tür sağlayıcısı uygulamak istediğinizi düşünün:
Normal ifadenin geçerli olup olmadığını doğrulama.
Normal ifadedeki herhangi bir grup adını temel alan eşleşmelerde adlandırılmış özellikler sağlama.
Bu bölümde, normal ifade deseninin bu avantajları sağlamak için parametreleştirdiğini bir RegexTyped tür oluşturmak için tür sağlayıcılarının nasıl kullanılacağı gösterilmektedir. Sağlanan desen geçerli değilse derleyici bir hata bildirir ve tür sağlayıcısı grupları desenden ayıklayabilir, böylece eşleşmelerde adlandırılmış özellikleri kullanarak bunlara erişebilirsiniz. Bir tür sağlayıcısı tasarlarken, kullanıma sunulan API'nin son kullanıcılara nasıl görünmesi gerektiğini ve bu tasarımın .NET koduna nasıl çevrileceğini göz önünde bulundurmalısınız. Aşağıdaki örnekte, alan kodunun bileşenlerini almak için böyle bir API'nin nasıl kullanılacağı gösterilmektedir:
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 örnekte, tür sağlayıcısının bu çağrıları nasıl çevirdiği gösterilmektedir:
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 noktaları not edin:
Standart Regex türü parametreli
RegexTypedtürü temsil eder.Oluşturucu
RegexTyped, Regex oluşturucusunun bir çağrısına neden olur ve desen için statik tür bağımsız değişkenini geçirir.yönteminin
Matchsonuçları standart Match türle temsil edilir.Adlandırılmış her grup sağlanan bir özelliğe neden olur ve özelliğe erişim, eşleşmenin
Groupskoleksiyonunda bir dizin oluşturucunun kullanılmasına neden olur.
Aşağıdaki kod, böyle bir sağlayıcıyı uygulamaya yönelik mantığın temelidir ve bu örnek sağlanan türe tüm üyelerin eklenmesini atlar. Eklenen her üye hakkında bilgi için bu konunun devamında yer alan uygun 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 noktaları not edin:
Tür sağlayıcısı iki statik parametre alır:
patternzorunlu olan ve isteğe bağlı olan (varsayılan bir değer sağlandığındanoptions).Statik bağımsız değişkenler sağlandıktan sonra normal ifadenin bir örneğini oluşturursunuz. Regex hatalı biçimlendirilmişse bu örnek bir özel durum oluşturur ve bu hata kullanıcılara bildirilir.
Geri çağırma fonksiyonu
DefineStaticParametersiçinde, bağımsız değişkenler sağlandıktan sonra döndürülecek türü tanımlarsınız.Bu kod, IntelliSense deneyiminin sorunsuz kalması için true olarak ayarlanır
HideObjectMethods. Bu öznitelik, sağlanan bir nesne içinEquals,GetHashCode,FinalizeveGetTypeüyelerinin IntelliSense listelerinden gizlenmeye neden olur.Yönteminin temel türü olarak kullanırsınız
obj, ancak sonraki örnekte gösterildiği gibi bu türün çalışma zamanı gösterimi olarak birRegexnesnesi kullanacaksınız.Oluşturucuya yapılan
Regexçağrı, normal bir ifade geçerli olmadığında bir ArgumentException oluşturur. Derleyici bu özel durumu yakalar ve derleme zamanında veya Visual Studio düzenleyicisinde kullanıcıya bir hata iletisi bildirir. Bu özel durum, normal ifadelerin bir uygulama çalıştırılmadan doğrulanmasına olanak tanır.
Yukarıda tanımlanan tür, anlamlı yöntemler veya özellikler içermediğinden henüz kullanışlı değildir. İlk olarak statik IsMatch bir 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, bir dizeyi giriş olarak alan ve döndüren bir IsMatchyöntemi booltanımlar. Tek karmaşık bölüm, bağımsız değişkenin args tanım içinde InvokeCode kullanılmasıdır. Bu örnekte, args bu yöntemin argümanlarını temsil eden alıntıların bir listesidir. Yöntem bir örnek yöntemiyse, ilk bağımsız değişken this argümanını temsil eder. Ancak, statik bir yöntem için bağımsız değişkenlerin tümü yalnızca yöntemin açık bağımsız değişkenleridir. Alıntılanan değerin türünün belirtilen dönüş türüyle (bu örnekte bool) eşleşmesi gerektiğini unutmayın. Bu kodun, IntelliSense aracılığıyla sağlayabileceğiniz yararlı belgeler içerdiğinden emin olmak için AddXmlDoc yöntemini kullandığını unutmayın.
Ardından bir örnek Match yöntemi ekleyin. Ancak, gruplara güçlü tipte erişim sağlanması için bu yöntem, belirtilen Match türde bir değer döndürmelidir. Bu nedenle, Match türünü önce bildirirsiniz. Bu tür, statik bağımsız değişken olarak sağlanan desene bağlı olduğundan, parametrelerle tanımlanan türün içinde yer almalıdır.
let matchTy =
ProvidedTypeDefinition(
"MatchType",
baseType = Some baseTy,
hideObjectMethods = true)
ty.AddMember matchTy
Ardından her grup için Eşleştirme türüne bir özellik eklersiniz. Çalışma zamanında bir eşleşme bir Match değer olarak temsil edilir, bu nedenle özelliği tanımlayan alıntı, ilgili grubu almak için dizine alınmış özelliği Groups 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($"""Gets the ""{group}"" group from this match""")
matchTy.AddMember prop
Sağlanan özelliğe XML belgeleri eklediğinizi de unutmayın. Ayrıca, bir GetterCode işlevi sağlandığında bir özelliğin okunabileceğini ve bir SetterCode işlevi sağlandığında özelliğin yazılabileceğini, dolayısıyla sonuçta elde edilen özelliğin sadece okunabilir olduğunu unutmayın.
Artık şu Match türde bir değer 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
Nesne yöntemi oluşturduğunuz için, args[0], yöntemin çağrıldığı RegexTyped nesnesini temsil eder ve args[1] giriş argümanını ifade eder.
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 bir .NET Regex örneğinin oluşturulmasını siler ve sağlanan türün silinmesi nedeniyle obj bir nesneye yeniden kutulanı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 tamamlandı ve son hali:
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ının nasıl oluşturulacağı açıklanmıştır. Sağlayıcı statik parametreyi denetler ve değerine göre işlemler sağlar.
Yerel veriler tarafından desteklenen bir tür sağlayıcısı
Genellikle tür sağlayıcılarının api'leri yalnızca statik parametrelere değil, aynı zamanda yerel veya uzak sistemlerden gelen bilgilere göre sunmasını isteyebilirsiniz. Bu bölümde, yerel veri dosyaları gibi yerel verileri temel alan tür sağlayıcıları açıklanmıştı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ılır:
| Mesafe (ölçüm) | Saat (saniye) |
|---|---|
| 50.0 | 3.7 |
| 100.0 | 5.2 |
| 150.0 | 6.4 |
Bu bölüm, Distance türünde bir özelliğe ve float<meter> türünde bir Time özelliğe sahip satırları almak için kullanabileceğiniz bir float<second> türü sağlamanın nasıl yapılacağını gösterir. Kolaylık olması için aşağıdaki varsayımlar yapılır:
Üst bilgi adları birimsizdir veya "Ad (birim)" biçimindedir 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.
Birimler, bileşik (örneğin, metre/saniye) yerine basittir (örneğin, metre).
Tüm sütunlar kayan nokta verileri içerir.
Daha kapsamlı bir sağlayıcı bu kısıtlamaları gevşetecek.
İlk adım da API'nin nasıl görüneceğini göz önünde bulundurmaktır. Önceki tablonun içeriğine sahip bir info.csv dosya (virgülle ayrılmış biçimde) göz önüne alındığında, sağlayıcı kullanıcıları aşağıdaki örneğe benzer bir kod yazabilmelidir:
let info = new MiniCsv<"info.csv">()
for row in info.Data do
let time = row.Time
printfn $"{float time}"
Bu durumda, derleyicinin bu çağrıları aşağıdaki örneğe benzer bir şeye dönüştürmesi gerekir:
let info = new CsvFile("info.csv")
for row in info.Data do
let (time:float) = row[1]
printfn $"%f{float time}"
En uygun çeviri için tür sağlayıcısının derlemesinde gerçek bir CsvFile tür tanımlaması gerekir. Tür sağlayıcıları genellikle önemli mantığı sarmalamada birkaç yardımcı tür ve yöntem kullanır. Ölçüler çalışma zamanında silindiğinden, bir satırın silinmiş türü olarak float[] kullanabilirsiniz. Derleyici, farklı sütunları farklı ölçü türlerine sahip olarak ele alır. Örneğin, örneğimizdeki ilk sütun türüne float<meter>, ikinci sütunda ise float<second>vardır. Ancak, silinen gösterim 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 ->
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 noktaları not edin:
Aşırı yüklenmiş oluşturucular özgün dosyanın veya aynı şemaya sahip bir dosyanın okunmasına izin verir. Bu düzen, yerel veya uzak veri kaynakları için bir tür sağlayıcısı yazdığınızda yaygındır ve bu desen, uzak veriler için şablon olarak yerel bir dosyanın kullanılmasına izin verir.
Göreli dosya adlarını çözümlemek için tür sağlayıcısı oluşturucusunda geçirilen TypeProviderConfig değerini kullanabilirsiniz.
Sağlanan özelliklerin
AddDefinitionLocationkonumunu tanımlamak için yöntemini kullanabilirsiniz. Bu nedenle, sağlanan bir özellikte kullanırsanızGo To Definition, CSV dosyası Visual Studio'da açılır.ProvidedMeasureBuildertürünü kullanarak SI birimlerini arayabilir ve ilgilifloat<_>türlerini oluşturabilirsiniz.
Önemli Dersler
Bu bölümde, veri kaynağının kendisinde bulunan basit bir şemayla yerel bir veri kaynağı için tür sağlayıcısının nasıl oluşturulacağı açıklanmıştır.
Daha Fazla
Aşağıdaki bölümlerde daha fazla çalışma önerileri yer almaktadır.
Silinen Türler için Derlenmiş Koda Bir Bakış
Size bazı fikirler vermek için, tür sağlayıcısının kullanımının yayılan koda nasıl karşılık geldiğini öğrenmek adına, bu konunun önceki bölümlerinde kullanılan HelloWorldTypeProvider öğesine bakarak aşağıdaki işlevi inceleyin.
let function1 () =
let obj1 = Samples.HelloWorldTypeProvider.Type1("some data")
obj1.InstanceProperty
İşte, ildasm.exekullanılarak decompile edilmiş sonucun kodunun bir görüntüsü:
.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 gösterildiği gibi, türü Type1 ve özelliği InstanceProperty ile ilgili tüm bahsetmeler silindi, yalnızca çalışma zamanı türlerine yönelik işlemler kaldı.
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özlemleyin.
tr-TR: Bağlantı Protokolleri için Sağlayıcılar Genel olarak, OData veya SQL bağlantıları gibi veri ve hizmet bağlantı protokolleri için çoğu sağlayıcı DLL'sinin adları TypeProvider veya TypeProviders ile bitmelidir. Örneğin, aşağıdaki dizeye benzeyen bir DLL adı kullanın:
Fabrikam.Management.BasicTypeProviders.dll
Sağlanan türlerinizin ilgili ad alanının üyesi olduğundan emin olun ve uyguladığınız bağlantı protokollerini belirtin:
Fabrikam.Management.BasicTypeProviders.WmiConnection<…>
Fabrikam.Management.BasicTypeProviders.DataProtocolConnection<…>
Genel Kodlama için Yardımcı Program Sağlayıcıları. Normal ifadeler için olduğu gibi bir yardımcı program türü sağlayıcısı için, aşağıdaki örnekte gösterildiği gibi tür sağlayıcısı 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ğlanır ve yalnızca veri sağlar. Bu durumda, TypeProvider son ekini bırakmanız ve .NET adlandırma kuralları için normal kuralları kullanmanız gerekiyor.
#r "Fabrikam.Data.Freebase.dll"
let data = Fabrikam.Data.Freebase.Astronomy.Asteroids
Daha fazla bilgi için bu konunun ilerleyen bölümlerinde açıklanan tasarım kuralına bakın GetConnection .
Tür Sağlayıcıları için Tasarım Desenleri
Aşağıdaki bölümlerde, tür sağlayıcıları yazarken kullanabileceğiniz tasarım desenleri açıklanmaktadır.
GetConnection Tasarım Deseni
Tür sağlayıcılarının çoğu, aşağıdaki örnekte gösterildiği gibi FSharp.Data.TypeProviders.dll'daki tür sağlayıcıları tarafından kullanılan GetConnection şablonunu kullanacak şekilde yazı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 Desteklenen Tip Sağlayıcıları
Uzak veriler ve hizmetler tarafından yedeklenen bir tür sağlayıcısı oluşturmadan önce, bağlı programlamanın doğasında bulunan bir dizi sorunu göz önünde bulundurmanız gerekir. Bu sorunlar aşağıdaki konuları içerir:
şema eşlemesi
şema değişikliği 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 destekleyici sorgular
kimlik bilgileri ve kimlik doğrulaması
Bu konu başlığında bu sorunlar daha fazla keşfedilmez.
Ek Yazma Teknikleri
Kendi tür sağlayıcılarınızı yazarken aşağıdaki ek teknikleri kullanmak isteyebilirsiniz.
İsteğe Bağlı 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 Tip Örneklendirmeleri Sağlama
sağlanan üyeleri (imzaları dizi türlerini, byref türlerini ve genel türlerin örneklemelerini içerir) normal MakeArrayType, MakePointerType ve MakeGenericType'yi, Type'ün herhangi bir örneğinde, ProvidedTypeDefinitions dahil olmak üzere, kullanarak oluşturursunuz.
Uyarı
Bazı durumlarda ProvidedTypeBuilder.MakeGenericType içinde yardımcıyı kullanmanız gerekebilir. Daha fazla ayrıntı için Tür Sağlayıcısı SDK'sı belgelerine bakın.
Ölçü Birimi Sağlama Ek Açıklamaları
ProvidedTypes API'si, ölçüm ek açıklamaları sağlamak için yardımcı araçlar sunar. Örneğin, float<kg> türünü 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])
türünü Nullable<decimal<kg/m^2>>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 |]
Project-Local veya Script-Local Kaynaklarına Erişme
Tür sağlayıcısının her örneğine, oluşturma sırasında bir TypeProviderConfig değer verilebilir. Bu değer sağlayıcının "çözümleme klasörünü" (derlemenin proje klasörü veya betik içeren dizin), başvuruda bulunılan derlemelerin listesini ve diğer bilgileri içerir.
Geçersiz kılma
Sağlayıcılar, F# dil hizmetine şema varsayımlarının değişmiş olabileceğini bildirmek için geçersizleştirme sinyalleri oluşturabilir. Geçersizleştirme oluştuğunda, sağlayıcı Visual Studio'da barındırılıyorsa tür denetimi yeniden yapılır. Sağlayıcı F# Interactive'de veya F# Derleyicisi tarafından (fsc.exe) barındırıldığında, bu sinyal yoksayılacaktır.
Şema Bilgilerini Önbelleğe Alma
Sağlayıcılar genellikle şema bilgilerine erişimi önbelleğe almalıdır. Önbelleğe alınan veriler, statik parametre olarak veya kullanıcı verileri olarak verilen bir dosya adı kullanılarak depolanmalıdır. Şema önbelleğe almanın bir örneği, LocalSchemaFile derlemesindeki tür sağlayıcılarında bulunan 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 dosyadaki şema bilgilerini kullanmaya yönlendirir. Önbelleğe alınmış şema bilgilerini kullanmak için statik parametresini ForceUpdatefalseolarak da ayarlamanız gerekir. Çevrimiçi ve çevrimdışı veri erişimini etkinleştirmek için benzer bir teknik kullanabilirsiniz.
Destekleme Montajı
Bir .dll veya .exe dosyasını derlediğinizde, oluşturulan türler için destekleyici .dll dosyası statik olarak oluşturulan derlemeye bağlanır. Bu bağlantı, Ara Dil (IL) türü tanımları ve yönetilen kaynaklar yedekleme derlemesinden son derlemeye kopyalanarak oluşturulur. F# Etkileşimli'yi kullandığınızda, destek .dll dosyası kopyalanmaz ve bunun yerine doğrudan F# Etkileşimli işlemine yüklenir.
Tür Sağlayıcılarından Özel Durumlar ve Tanılamalar
Sağlanan türlerin üyelerinin her türlü kullanımı özel durumlar oluşturabilir. Her durumda, bir tür sağlayıcısı özel durum oluşturursa, konak derleyicisi hatayı belirli bir tür sağlayıcısına bağlar.
Tür sağlayıcısı özel durumları hiçbir zaman iç derleyici hatalarına neden olmamalıdır.
Tür sağlayıcıları uyarıları bildiremez.
Bir tür sağlayıcısı F# derleyicisinde, F# geliştirme ortamında veya F# Etkileşimli’de barındırıldığında, bu sağlayıcıdan kaynaklanan tüm özel durumlar yakalanır. Mesaj özelliği her zaman hata metnidir ve yığın izleme bilgisi görüntülenmez. Özel durum oluşturacaksanız aşağıdaki örnekleri oluşturabilirsiniz:
System.NotSupportedException, ,System.IO.IOExceptionSystem.Exception.
Oluşturulan Türleri Sağlama
Şimdiye kadar, bu belgede silinen türlerin nasıl sağlandığı açıklanmış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# dilinde tür sağlayıcısı mekanizmasını da kullanabilirsiniz. Tür tanımı kullanarak oluşturulan ve sağlanan türlere başvurmanız gerekir.
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, oluşturulan türleri sağlamaya yönelik yalnızca sınırlı desteğe sahiptir. Oluşturulan tür tanımı için aşağıdaki deyimlerin true olması gerekir:
isErasedolarak ayarlanmalıdırfalse.Oluşturulan tür, oluşturulan kod parçaları için bir kapsayıcıyı temsil eden yeni oluşturulan
ProvidedAssembly()öğesine eklenmelidir.Sağlayıcının, diskte eşleşen bir .dll dosyası ile desteklenen gerçek bir .NET .dll dosyasına sahip bir derlemesi olmalıdır.
Kurallar ve Sınırlamalar
Tür sağlayıcıları yazarken aşağıdaki kuralları ve sınırlamaları göz önünde bulundurun.
Sağlanan türler erişilebilir olmalıdır.
Sağlanan tüm türler iç içe olmayan türlerden erişilebilir olmalıdır. İç içe olmayan türler, TypeProviderForNamespaces oluşturucusuna veya AddNamespace çağrısına yapılan bir çağrıda verilir. Örneğin, sağlayıcı bir tür StaticClass.P : Tsağlıyorsa, T'nin iç içe olmayan bir tür olduğundan veya bir türün altında iç içe olduğundan emin olmanız gerekir.
Örneğin, bazı sağlayıcıların, bu DataTypes türlerini içeren T1, T2, T3, ... gibi statik bir sınıfı vardır. Aksi takdirde hata, A derlemesindeki T türüne başvurunun bulunduğunu, ancak türün bu derlemede bulunamadığını belirtir. Bu hata görüntülenirse, tüm alt türlerinize sağlayıcı türlerinden ulaşılabildiğini doğrulayın. Not: Bu T1, T2, T3... türler, anında türler olarak adlandırılır. Bunları erişilebilir bir ad alanına veya üst türe eklemeyi unutmayın.
Tür Sağlayıcısı Mekanizmasının Sınırlamaları
F# içindeki tür sağlayıcısı mekanizması aşağıdaki sınırlamalara sahiptir:
F# dilindeki 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ını yararlı bulabilirsiniz:
Visual Studio'nun iki örneğini çalıştırma
Bir örnekte tür sağlayıcısı geliştirebilir ve sağlayıcıyı diğerinde test edebilirsiniz çünkü test IDE, tür sağlayıcısının yeniden oluşturulmasını engelleyen .dll dosyasına kilitlenir. Bu nedenle, sağlayıcı ilk örnekte oluşturulurken Visual Studio'nun ikinci örneğini kapatmanız ve sağlayıcı oluşturulduktan sonra ikinci örneği yeniden açmanız gerekir.
fsc.exe çağrılarını kullanarak tür sağlayıcılarında 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# Etkileşimli Derleyici)
devenv.exe (Visual Studio)
Test betiği dosyasında (örneğin, script.fsx) fsc.exe kullanarak tür sağlayıcılarının hatalarını en kolay şekilde ayıklayabilirsiniz. Bir komut isteminden hata ayıklayıcı başlatabilirsiniz.
devenv /debugexe fsc.exe script.fsx
Stdout'a yazdırma günlüğünü kullanabilirsiniz.