Aracılığıyla paylaş


Xamarin.iOS'ta NSObject'in genel alt sınıfları

NSObjects ile genel değerleri kullanma

öğesinin alt sınıflarında NSObjectgenel 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 NSObjectsaçı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 NSObjectparametresidir, 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 Ttam 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 NSObjectolacak ş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ı NSObjectiç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 Tiç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.