2012-07-27 11 views
21

olarak boş yok:Tür uygun bir değere örnek program için

type public MyClass(reasonForLiving:string) = 
    member x.ReasonForLiving with get() = reasonForLiving 

let classFactory() = MyClass("up to you") 
let live() = 
    let instance = classFactory() 
    if instance = null then raise(System.Exception("null is not living... that's why OO languages die from bugs")) 
    instance 

hatası alıyorum "türü 'Sınıfım' uygun bir değer olarak boş yok" Ben bu sınıfı kullanmak gitmek örtük olarak yazılan işlevlerin bir dönüş değeri olarak ve numaralı ile karşılaştır (C# bağımlılık enjeksiyonuyla uyumluluk gereksinimlerinin b/c'si F # seçenek türlerine güvenemiyorum).

Kolayca için boş çek değiştirerek bunu düzeltebilirsiniz:

if instance :> obj = null then 

Ancak, bu tamamen "yanlış" olduğunu ("hissetmek") biliyorum. Özellikle de, MyClass'ın kutulu olması gerekmeyen bir referans türü olduğunu düşündüğüm zaman (C# arka planından bahsediyorum).

"F # Değer Kısıtlaması" nı ve bunun tür çıkarımını nasıl etkilediğini okudum, ancak bu senaryo için nasıl geçerli olduğunu göz ardı edemiyorum.

S: Bunu yapmanın başka bir yolu var mı?

Kenara # 1: Sınıfım bir olduğunu ... düşünmeden System.Nullable çalıştım: hatası almanın daha basit bir yöntem ... Kenara # 2

type public MyClass(reasonForLiving:string) = 
    member x.ReasonForLiving with get() = reasonForLiving 
let nullMyClass : MyClass = null 

bulundu Referans türü ve değil Nullable < _> gerektiren bir değer türü (struct). Öyleyse, bana sadece bir referans tipi ile uğraştığımı ve bana bir nesnenin neden bu işi yaptığını merak etmeme yol açtığını söyler.

Güncelleme: İlgilenen herkes için, aşağıdaki üç işlevle Ortak Hizmet Bulucu için tek bir çözüm olarak kullandım.

let private getServiceLocator() = 
    try Some(Microsoft.Practices.ServiceLocation.ServiceLocator.Current) 
    with | _ -> None 

let private getService serviceFactory = 
    let serviceLocator = getServiceLocator() 
    let service = match serviceLocator with 
        | None -> serviceFactory() 
        | _ -> 
        match serviceLocator.Value.GetInstance<'a>() with 
        | null -> serviceFactory() 
        | svc -> svc 
    match service with 
    | null -> None 
    | _ -> Some(service) 

let private getRequiredService serviceFactory = 
    let service = getService serviceFactory 
    match service with 
    | None -> raise(MissingServiceException("")) 
    | _ -> service.Value 

cevap

39

kullanın [<AllowNullLiteral>] niteliğini: Varsayılan olarak

[<AllowNullLiteral>] 
type public MyClass(reasonForLiving:string) = 
    member x.ReasonForLiving with get() = reasonForLiving 

, F # türlerini hizmet sınıfı F # tanımlanır eğer öyleyse, null adlı desteklemelidir istenen Her hizmet, sen [<AllowNullLiteral>] eklemeniz gerekir null izin vermeyin (göklere teşekkür!). Bu öznitelik, diğer .NET dilleriyle birlikte çalışmak için kullanışlıdır ve null ile atama/karşılaştırma olanağı sağlar. AllowNullLiteral özniteliği ile

+0

Doh! Bunu gördükten sonra, MSDN "Boş Değerler (F #)" üzerindeki üçüncü cümleden tanıdım: http://msdn.microsoft.com/en-us/library/dd233197(v=vs.110).aspx –

+2

Sadece add - –

+0

John'u kullanmazsanız, 'Option' t 'kullanmak daha idiomatiktir - Evet, Option'u kullanamadığmdan bahsetmiştim. Bu yüzden, C# 'ye maruz kalan her sınıfın bir [# AllowNullLiteral>]' a ihtiyaç duyması C# dev olarak çalışacak ... :( –

14

sorun null Nesnelerinizi karşılaştırmak için izin vermeye ek olarak, aynı zamanda mümkün için null Nesnelerinizi set sağlamasıdır.

let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null) 

Sonra yerine if instance = null then yapmaktansa, bunun yerine if isNull instance then yapın: Bu kullanım örneği için arzu olmadığını varsayarsak

gözlemlenemeyen performans etkisi olan kolay alternatif var.

Bu, herhangi bir referans türü (kayıtlar ve DU'lar dahil) için çalışacaktır, ancak F # öğelerinizin nesnelerini her iki dünyanın en iyisi olan F # değerine ayarlama olanağı sunmaz.

+3

Bu yaklaşımı bir kez bir büyük ish projesinde kullandım, ama pişman oldum, bir tür boş olabilirse (F # ya da interop nedeniyle) açık olması en iyisidir. Neyin daha iyi olduğu, null-aktif bir paternin tanımlanması veya null ile eşleştirilen değerlerin tanımlanması -> ... '? Sonunda, bu gibi geçici çözümler hacky hissediyordu.İşbirliği için, türlerine sadece []' ekleyin ve kucaklama null – Daniel

+0

@Daniel: Ben im almak OP'nin sadece C# 'dan F # türlerini kullanmak istediği baskisi, bu yüzden ne kadar doğru etkileşimin devam ettiğini bilmiyorum ... – ildjarn

+0

Yukarıdaki ismin tanımı, sözdizimi hatası verdi: '' Açık tip parametreleri sadece modülde kullanılabilir veya üye yerine bu çalıştı bindings'': '' isnull (x: obj) = obj.ReferenceEquals (x, Unchecked.defaultof <_>) '' parametre otomatik bağlama yana tabii , herhangi bir değeri kabul nesneyi yukarı itmek (sonuçta kutu çalışması ile). Bu nedenle, başvuru dışı değer için derleyici uyarısı kaybolur. – George

İlgili konular