C # - ประเภททั่วไปหลายรายการในหนึ่งรายการ


153

อาจเป็นไปไม่ได้ แต่ฉันมีชั้นนี้:

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

มีมากกว่านั้น แต่ขอให้เรียบง่าย ประเภททั่วไป (DataType) ถูก จำกัด ประเภทค่าโดยคำสั่งที่ สิ่งที่ฉันต้องการจะทำคือมีรายการของวัตถุ Metadata ประเภทต่าง ๆ (DataType) เช่น:

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

เป็นไปได้ไหม


24
ฉันสงสัยว่ามีประโยชน์จริง ๆ กับวิธีการในคำตอบด้านล่างเมื่อเทียบกับเพียงแค่ใช้List<object>? พวกเขาจะไม่หยุดชกมวย / unboxing พวกเขาจะไม่ลบความจำเป็นในการคัดเลือกนักแสดงและท้ายที่สุดคุณจะได้รับMetadataวัตถุที่ไม่ได้บอกอะไรคุณเกี่ยวกับความจริงDataTypeฉันกำลังค้นหาวิธีแก้ปัญหาเหล่านั้น หากคุณกำลังจะประกาศอินเตอร์เฟส / คลาสเพียงเพื่อให้สามารถพิมพ์ชนิดทั่วไปที่นำไปปฏิบัติ / ที่ได้มาในรายการทั่วไปความแตกต่างของการใช้งานแบบList<object>อื่นที่ไม่ใช่เลเยอร์ที่ไม่มีความหมายนั้นเป็นอย่างไร
Saeb Amini

9
ทั้งคลาสฐานนามธรรมและอินเตอร์เฟสให้ระดับการควบคุมโดยการ จำกัด ประเภทขององค์ประกอบที่สามารถเพิ่มลงในรายการ ฉันยังไม่เห็นว่าการชกมวยเป็นอย่างไร
0b101010

3
แน่นอนถ้าคุณใช้. NET v4.0 หรือสูงกว่าความแปรปรวนร่วมเป็นวิธีแก้ปัญหา List<Metadata<object>>ไม่หลอกลวง
0b101010

2
@ 0b101010 ฉันคิดเหมือนกัน แต่ไม่อนุญาตให้มีความแปรปรวนในประเภทค่าได้ เนื่องจาก OP มีstructข้อ จำกัด จึงไม่ทำงานที่นี่ ดู
nawfal

@ 0b101010, ทั้งสองอย่าง จำกัด เฉพาะประเภทอ้างอิง, ชนิดของมูลค่าในตัวและโครงสร้างใด ๆ ยังสามารถเพิ่มได้ นอกจากนี้ในท้ายที่สุดคุณมีรายการMetaDataประเภทอ้างอิงแทนประเภทค่าดั้งเดิมของคุณที่ไม่มีข้อมูล (เวลารวบรวม) เกี่ยวกับประเภทมูลค่าพื้นฐานของแต่ละองค์ประกอบนั่นคือ"มวย" อย่างมีประสิทธิภาพ
Saeb Amini

คำตอบ:


195
public abstract class Metadata
{
}

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

5
ว้าว! ฉันไม่คิดว่ามันเป็นไปได้จริง ๆ ! คุณเป็นคนช่วยชีวิตมนุษย์!
Carl

2
+10 สำหรับสิ่งนี้! ฉันไม่ทราบว่าทำไมการรวบรวมนี้ .. สิ่งที่ฉันต้องการ!
Odys

ฉันมีปัญหาที่คล้ายกัน แต่คลาสทั่วไปของฉันขยายจากคลาสทั่วไปอื่นดังนั้นฉันไม่สามารถใช้วิธีแก้ปัญหาของคุณ ... แนวคิดใด ๆ ในการแก้ไขสำหรับสถานการณ์นี้
Sheridan

10
จะมีประโยชน์กับวิธีนี้เมื่อเทียบกับวิธีที่ง่ายList<object>? โปรดดูความคิดเห็นของฉันโพสต์ภายใต้คำถามของ OP
Saeb Amini

11
@SaebAmini รายการ <object> ไม่ได้แสดงเจตนาใด ๆ ต่อผู้พัฒนาและไม่ขัดขวางนักพัฒนาที่จะยิงตัวเองโดยการเพิ่มวัตถุที่ไม่ใช่ MetaData ลงในรายการอย่างผิดพลาด โดยใช้รายการ <MetaData> จะเข้าใจว่ารายการควรมีอะไร MetaData ส่วนใหญ่มีคุณสมบัติ / วิธีการสาธารณะที่ไม่ได้แสดงในตัวอย่างข้างต้น การเข้าถึงสิ่งเหล่านั้นผ่านออบเจ็กต์นั้นจำเป็นต้องใช้การร่ายที่ยุ่งยาก
Buzz

92

ทำตามคำตอบของ leppie ทำไมไม่สร้างMetaDataอินเทอร์เฟซ:

public interface IMetaData { }

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

มีคนบอกฉันได้ไหมว่าทำไมวิธีการนี้ถึงดีกว่า
Lazlo

34
เพราะไม่มีฟังก์ชั่นทั่วไปที่ใช้ร่วมกัน - ทำไมต้องเสียคลาสพื้นฐานในตอนนั้น? อินเตอร์เฟซที่จะเพียงพอ
FLQ

2
เพราะคุณสามารถใช้อินเทอร์เฟซใน struct
Damian Leszczyński - Vash

2
อย่างไรก็ตามการสืบทอดคลาสโดยใช้วิธีเสมือนจริงนั้นเร็วกว่าวิธีส่วนต่อประสานประมาณ 1.4 เท่า ดังนั้นหากคุณวางแผนที่จะใช้เมธอด / คุณสมบัติ MetaData (เสมือน) ที่ไม่ใช่ทั่วไปใน MetaData <DataType> ให้เลือกคลาสนามธรรมแทนอินเทอร์เฟซหากประสิทธิภาพเป็นกังวล มิฉะนั้นการใช้อินเตอร์เฟสอาจมีความยืดหยุ่นมากกว่า
TamusJRoyce

30

ฉันยังใช้รุ่นที่ไม่ใช่ทั่วไปโดยใช้newคำหลัก:

public interface IMetadata
{
    Type DataType { get; }

    object Data { get; }
}

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

การใช้อินเทอร์เฟซที่ชัดเจนถูกใช้เพื่ออนุญาตให้Dataสมาชิกทั้งสอง:

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; }
}

คุณสามารถรับประเภทค่าการกำหนดเป้าหมายเป็นเวอร์ชัน:

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)
    {}
}

สิ่งนี้สามารถขยายไปสู่ข้อ จำกัด ทั่วไปประเภทใดก็ได้


4
+1 เพียงเพราะคุณแสดงวิธีการใช้งาน ( DataTypeและobject Dataช่วยได้มาก)
Odys

4
ฉันดูเหมือนจะไม่สามารถเขียนตัวอย่างDeserialize<metadata.DataType>(metadata.Data);ได้ มันบอกฉันไม่สามารถแก้ไขข้อมูลเมตาสัญลักษณ์ วิธีการดึง DataType เพื่อใช้สำหรับวิธีการทั่วไป
Cœur
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.