Bir listede birden çok genel tür


153

Bu muhtemelen mümkün değil, ama bu sınıf var:

public class Metadata<DataType> where DataType : struct
{
    private DataType mDataType;
}

Daha fazlası var, ama basit tutalım. Genel tür (DataType) where deyimi tarafından değer türleriyle sınırlıdır. Ne yapmak istiyorum bu metadata nesnelerin değişen türleri (DataType) bir listesi var. Gibi:

List<Metadata> metadataObjects;
metadataObjects.Add(new Metadata<int>());
metadataObjects.Add(new Metadata<bool>());
metadataObjects.Add(new Metadata<double>());

Bu mümkün mü?


24
Acaba aşağıdaki cevaplardaki yaklaşımların sadece a List<object>? Boks / kutudan çıkmayı Metadatabırakmazlar , döküm ihtiyacını ortadan kaldırmazlar ve sonuçta size gerçek hakkında hiçbir şey söylemeyen bir nesne alıyorsunuz DataType, bu sorunları çözmek için bir çözüm arıyordum. Eğer bir arabirim / sınıf ilan edecekseniz, sadece gerçekleme listesine gerçekleyen / türetilmiş jenerik türü koymak adına, anlamsız bir katmandan başka bir katman kullanmaktan ne kadar farklıdırList<object> ?
Saeb Amini

9
Hem soyut temel sınıf hem de arabirim, listeye eklenebilecek öğelerin türünü kısıtlayarak bir derece kontrol sağlar. Boksun buna nasıl geldiğini de göremiyorum.
0b101010

3
Tabii ki, .NET v4.0 veya üstünü kullanıyorsanız, çözüm kovaryanstır. List<Metadata<object>>hile yapar.
0b101010

2
@ 0b101010 Ben de aynısını düşünüyordum, ama maalesef değer türlerinde varyansa izin verilmiyor. OP'nin bir structkısıtlaması olduğundan, burada çalışmaz. Bakınız
nawfal

@ 0b101010, Her ikisi de yalnızca referans türlerini kısıtlar, herhangi bir yerleşik değer türü ve herhangi bir yapı hala eklenebilir. Ayrıca, sonunda, MetaDataher bir öğenin temel değer türü hakkında (derleme zamanı) hiçbir bilgi içermeyen, orijinal değer türleriniz yerine referans türlerinin bir listesi vardır , bu da etkili bir şekilde "bokslama" dır.
Saeb Amini

Yanıtlar:


195
public abstract class Metadata
{
}

// extend abstract Metadata class
public class Metadata<DataType> : Metadata where DataType : struct
{
    private DataType mDataType;
}

5
Vaov! Bunun mümkün olduğunu gerçekten düşünmemiştim! Sen hayat kurtarıcısın dostum!
Carl

2
Bunun için +10! Bunun neden derlendiğini bilmiyorum .. Tam olarak ihtiyacım olan şey!
Odys

Benzer bir sorun var, ama benim genel sınıf başka bir genel sınıftan uzanır, bu yüzden çözümünü kullanamıyorum ... bu durum için bir düzeltme hakkında herhangi bir fikir?
Sheridan

10
Bu yaklaşımın bir basitle karşılaştırıldığında bir faydası var mı List<object>? lütfen OP'nin sorusu altında yayınlanan yorumuma bakın.
Saeb Amini

11
@SaebAmini List <object> bir geliştiriciye herhangi bir niyet göstermez ya da hatalı bir şekilde listeye MetaData olmayan bir nesne ekleyerek geliştiricinin kendilerini ayağa vurmasını engellemez. Bir Liste <MetaData> kullanarak listenin ne içermesi gerektiği anlaşılır. Büyük olasılıkla MetaData, yukarıdaki örneklerde gösterilmeyen bazı genel özelliklere / yöntemlere sahip olacaktır. Bunlara nesne aracılığıyla erişmek hantal bir oyuncu gerektirir.
Buzz

92

Lepie'nin cevabından sonra, neden MetaDatabir arayüz yapmıyorsunuz :

public interface IMetaData { }

public class Metadata<DataType> : IMetaData where DataType : struct
{
    private DataType mDataType;
}

Birisi bana bu yaklaşımın neden daha iyi olduğunu söyleyebilir mi?
Lazlo

34
Ortak bir işlevsellik paylaşılmadığından, neden bu konuda bir temel sınıf harcamalısınız? Bir arayüz yeterli
flq

2
Çünkü arayüzleri yapıda uygulayabilirsiniz.
Damian Leszczyński - Vash

2
Bununla birlikte, sanal yöntemler kullanan sınıf mirası, arabirim yöntemlerinden yaklaşık 1,4 kat daha hızlıdır. Bu nedenle, MetaData <DataType> içinde genel olmayan herhangi bir MetaData (sanal) yöntem / özellik uygulamayı planlıyorsanız, performansla ilgili bir sorun varsa, arabirim yerine soyut bir sınıf seçin. Aksi takdirde, bir arayüz kullanmak daha esnek olabilir.
TamusJRoyce

30

Ayrıca newanahtar kelimeyi kullanarak genel olmayan bir sürümünü kullandım :

public interface IMetadata
{
    Type DataType { get; }

    object Data { get; }
}

public interface IMetadata<TData> : IMetadata
{
    new TData Data { get; }
}

Her iki Dataüyeye de izin vermek için açık arabirim uygulaması kullanılır :

public class Metadata<TData> : IMetadata<TData>
{
    public Metadata(TData data)
    {
       Data = data;
    }

    public Type DataType
    {
        get { return typeof(TData); }
    }

    object IMetadata.Data
    {
        get { return Data; }
    }

    public TData Data { get; private set; }
}

Değer türlerini hedefleyen bir sürüm türetebilirsiniz:

public interface IValueTypeMetadata : IMetadata
{

}

public interface IValueTypeMetadata<TData> : IMetadata<TData>, IValueTypeMetadata where TData : struct
{

}

public class ValueTypeMetadata<TData> : Metadata<TData>, IValueTypeMetadata<TData> where TData : struct
{
    public ValueTypeMetadata(TData data) : base(data)
    {}
}

Bu, her türlü genel kısıtlamaya kadar genişletilebilir.


4
+1, sadece nasıl kullanılacağını gösterdiğiniz için ( DataTypeve object Dataçok yardımcı oldu)
Odys

4
Mesela yazamıyorum Deserialize<metadata.DataType>(metadata.Data);. Sembol meta verilerini çözemediğimi söylüyor . Genel bir yöntem için kullanmak için DataType nasıl alınır?
Cœur
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.