Xamarin.iOS'ta NSObject'in genel alt sınıfları
NSObjects ile genel değerleri kullanma
öğesinin alt sınıflarında NSObject
genel değerleri kullanmak mümkündür, örneğin UIView:
class Foo<T> : UIView {
public Foo (CGRect x) : base (x) {}
public override void Draw (CoreGraphics.CGRect rect)
{
Console.WriteLine ("T: {0}. Type: {1}", typeof (T), GetType ().Name);
}
}
Alt sınıfın NSObject
nesneleri çalışma zamanına kaydedildiğinden, türlerin Objective-C genel alt sınıflarıyla mümkün olan bazı sınırlamalar NSObject
vardır.
NSObject'in genel alt sınıfları için dikkat edilmesi gerekenler
Bu belgede, genel alt sınıfları için sınırlı destek kapsamındaki sınırlamalar ayrıntılı olarak NSObjects
açıklanır.
Üye İmzalarındaki Genel Tür Bağımsız Değişkenleri
Kullanıma sunulan Objective-C bir üye imzasında yer alan tüm genel tür bağımsız değişkenlerinin bir NSObject
kısıtlaması olmalıdır.
İyi:
class Generic<T> : NSObject where T: NSObject
{
[Export ("myMethod:")]
public void MyMethod (T value)
{
}
}
Neden: Genel tür parametresi bir NSObject
parametresidir, bu nedenle seçici imzası myMethod:
güvenli bir şekilde kullanıma sunulur Objective-C (her zaman NSObject
veya alt sınıfı olur).
Hatalı:
class Generic<T> : NSObject
{
[Export ("myMethod:")]
public void MyMethod (T value)
{
}
}
Neden: kodun çağırabileceği dışarı aktarılan üyeler Objective-C için imza Objective-C oluşturmak mümkün değildir, çünkü imza, genel türün T
tam türüne bağlı olarak farklılık gösterir.
İyi:
class Generic<T> : NSObject
{
T storage;
[Export ("myMethod:")]
public void MyMethod (NSObject value)
{
}
}
Neden: Dışarı aktarılan üye imzasının bir parçası olmadığı sürece kısıtlanmamış genel tür bağımsız değişkenlerine sahip olmak mümkündür.
İyi:
class Generic<T, U> : NSObject where T: NSObject
{
[Export ("myMethod:")]
public void MyMethod (T value)
{
Console.WriteLine (typeof (U));
}
}
Neden: T
Dışarı aktarılan MyMethod
içindeki Objective-C parametresi bir NSObject
olacak şekilde kısıtlanmış, kısıtlanmamış tür U
imzanın bir parçası değil.
Hatalı:
class Generic<T> : NSObject
{
public T Storage { get; }
public Generic(T value)
{
Storage = value;
}
}
[Register("Foo")]
class Foo: NSView
{
[Export("Test")]
public Generic<int> Test { get; set; } = new Generic<int>(22);
[Export("Test1")]
public Generic<object> Test1 { get; set; } = new Generic<object>(new object());
[Export("Test2")]
public Generic<NSObject> Test2 { get; set; } = new Generic<NSObject>(new NSObject());
}
Neden: henüz registrar bu senaryoyu desteklemez. Daha fazla bilgi için bu GitHub sorunlarına bakın.
Genel Türlerin Örneklemeleri Objective-C
'den Objective-C genel türlerin örneğine izin verilmiyor. Bu durum genellikle yönetilen bir tür bir xib veya görsel taslakta kullanıldığında oluşur.
Yerel bir örnekten C# nesnesi Objective-C oluşturmanın Xamarin.iOS yolu) alan IntPtr
bir oluşturucuyu kullanıma sunan bu sınıf tanımını göz önünde bulundurun:
class Generic<T> : NSObject where T : NSObject
{
public Generic () {}
public Generic (IntPtr ptr) : base (ptr) {}
}
Yukarıdaki yapı iyi olsa da, çalışma zamanında bunun bir örneğini oluşturmaya çalışılırsa Objective-C bu bir özel durum oluşturur.
Bunun nedeni Objective-C , genel türler kavramı olmaması ve oluşturulacak tam genel türü belirtememesidir.
Bu sorun, genel türün özelleştirilmiş bir alt sınıfı oluşturularak geçici olarak çözümlenebilir. Örneğin:
class Generic<T> : NSObject where T : NSObject
{
public Generic () {}
public Generic (IntPtr ptr) : base (ptr) {}
}
class GenericUIView : Generic<UIView>
{
}
Artık belirsizlik yok, sınıf GenericUIView
xibs veya görsel taslaklarda kullanılabilir.
Genel yöntemler için destek yok
Genel yöntemlere izin verilmez.
Aşağıdaki kod derlenmez:
class MyClass : NSObject
{
[Export ("myMethod")]
public void MyMethod<T> (T argument)
{
}
}
Neden: Xamarin.iOS yöntemi'nden çağrıldığında tür bağımsız değişkeni T
için hangi türün kullanılacağını bilmediğinden Objective-C buna izin verilmez.
Bunun alternatifi, özelleştirilmiş bir yöntem oluşturmak ve bunu dışarı aktarmaktır:
class MyClass : NSObject
{
[Export ("myMethod")]
public void MyUIViewMethod (UIView argument)
{
MyMethod<UIView> (argument);
}
public void MyMethod<T> (T argument)
{
}
}
Dışarı aktarılan statik üyeye izin verilmiyor
statik üyelerini Objective-C , genel bir alt sınıfı NSObject
içinde barındırılıyorsa kullanıma sunun.
Desteklenmeyen senaryo örneği:
class Generic<T> : NSObject where T : NSObject
{
[Export ("myMethod:")]
public static void MyMethod ()
{
}
[Export ("myProperty")]
public static T MyProperty { get; set; }
}
Neden: Genel yöntemlerde olduğu gibi, Xamarin.iOS çalışma zamanının da genel tür bağımsız değişkeni T
için hangi tür kullanılacağını bilmesi gerekir.
Örneğin üyeler için örneğin kendisi kullanılır (çünkü hiçbir zaman bir örnek Generic<T>
olmayacaktır, her zaman olacaktır Generic<SomeSpecificClass>
), ancak statik üyeler için bu bilgiler mevcut değildir.
Söz konusu üye tür bağımsız değişkenini T
herhangi bir şekilde kullanmasa bile bunun geçerli olduğunu unutmayın.
Bu örnekteki alternatif, özelleştirilmiş bir alt sınıf oluşturmaktır:
class GenericUIView : Generic<UIView>
{
[Export ("myUIViewMethod")]
public static void MyUIViewMethod ()
{
MyMethod ();
}
[Export ("myProperty")]
public static UIView MyUIViewProperty {
get { return MyProperty; }
set { MyProperty = value; }
}
}
class Generic<T> : NSObject where T : NSObject
{
public static void MyMethod () {}
public static T MyProperty { get; set; }
}
Performans
Statik registrar , genel bir türdeki dışarı aktarılan üyeyi derleme zamanında çözümleyemez. Genellikle olduğu gibi çalışma zamanında aranması gerekir. Bu, böyle bir yöntemin Objective-C çağrılması, genel olmayan sınıflardan üyeleri çağırmaktan biraz daha yavaş olduğu anlamına gelir.