ทางลัดสำหรับสร้างรายการเดียวใน C #


140

ใน C # มีทางลัดแบบอินไลน์เพื่อสร้างอินสแตนซ์รายการ <T> ด้วยรายการเดียวหรือไม่

ฉันกำลังทำ:

new List<string>( new string[] { "title" } ))

การมีรหัสนี้ทุกที่จะช่วยลดความสามารถในการอ่าน ฉันเคยคิดจะใช้วิธียูทิลิตี้เช่นนี้:

public static List<T> SingleItemList<T>( T value )
{
    return (new List<T>( new T[] { value } ));
}

ดังนั้นฉันสามารถทำได้:

SingleItemList("title");

มีวิธีที่สั้นกว่า / สะอาดกว่านี้ไหม?

ขอบคุณ.

คำตอบ:


253

เพียงใช้สิ่งนี้:

List<string> list = new List<string>() { "single value" };

คุณยังสามารถละเว้น () วงเล็บปีกกา:

List<string> list = new List<string> { "single value" };

อัปเดต: แน่นอนว่าสิ่งนี้ใช้ได้กับมากกว่าหนึ่งรายการ:

List<string> list = new List<string> { "value1", "value2", ... };

6
ใส่ตัวอักษร 1 ตัวในวงเล็บของตัวเลือกแรกเพื่อให้มีการจัดสรรพื้นที่เก็บข้อมูลสำหรับพื้นที่เดียวแทนที่จะเป็นค่าเริ่มต้น 10
Joel Coehoorn

5
ค่าเริ่มต้นจะกลายเป็น 4 ฉันเชื่อว่า: new List <string> {"Hello"} .Capacity == 4
Jon Skeet

40
var list = new List<string>(1) { "hello" };

คล้ายกับที่คนอื่นโพสต์ไว้มากยกเว้นว่าจะต้องจัดสรรพื้นที่สำหรับรายการเดียวในตอนแรกเท่านั้น

แน่นอนว่าหากคุณรู้ว่าคุณจะเพิ่มสิ่งต่างๆมากมายในภายหลังอาจไม่ใช่ความคิดที่ดี แต่ก็ยังควรกล่าวถึงสักครั้ง


ความจุตั้งไว้ที่หนึ่ง ฉันโหวตให้สี่คำตอบในหน้านี้รวมทั้งของ Jon Skeet แต่ฉันคิดว่าคำตอบนี้ถูกต้องที่สุด
The Lonely Coder

28

ความคิดของ Michael ในการใช้วิธีการขยายนำไปสู่สิ่งที่ง่ายกว่า:

public static List<T> InList<T>(this T item)
{
    return new List<T> { item };
}

คุณสามารถทำได้:

List<string> foo = "Hello".InList();

ฉันไม่แน่ใจว่าฉันชอบหรือไม่ใจคุณ ...


1
ฉันก็ไม่แน่ใจเหมือนกันว่าชอบ: นี่ไม่ใช่นามสกุล "แปลก ๆ " ของประเภทสตริง (เช่น) หรือเปล่า
M4N

1
ฉันยังไม่ได้ใช้วิธีการขยายในหนังสือของคุณจอน :-) มันดูแปลก ๆ แต่ฉันชอบยูทิลิตี้ของมัน ขอบคุณมาร์ตินและจอน
Ryan Ische

2
@ มาร์ติน: เป็นนามสกุลที่แปลกทุกประเภท โดยทั่วไปสิ่งนี้ไม่น่าสนใจ แต่เป็นแนวคิดทั่วไปที่น่าสนใจ
Jon Skeet

4
มันใช้ภาษาเฉพาะโดเมนภายในบางภาษาโดยเฉพาะกับประเภทค่า ยกตัวอย่างเช่น clock.AlertUserIn (1.Minute) อ่านได้ดีกว่า clock.AlertUser (TimeSpan.FromMinutes (1));
Michael Meadows

17

คำตอบที่แตกต่างออกไปสำหรับข้อก่อนหน้าของฉันโดยพิจารณาจากการเปิดรับGoogle Java Collections :

public static class Lists
{
    public static List<T> Of<T>(T item)
    {
        return new List<T> { item };
    }
}

จากนั้น:

List<string> x = Lists.Of("Hello");

ฉันแนะนำให้ลองดู GJC - มันมีสิ่งที่น่าสนใจมากมาย (โดยส่วนตัวแล้วฉันจะไม่สนใจแท็ก "alpha" - เป็นเพียงเวอร์ชันโอเพ่นซอร์สซึ่งเป็น "อัลฟ่า" และใช้ API ภายในที่เสถียรและใช้งานหนักมาก .)



7

ใช้วิธีการขยายด้วยวิธีการผูกมัด

public static List<T> WithItems(this List<T> list, params T[] items)
{
    list.AddRange(items);
    return list;
}

สิ่งนี้จะช่วยให้คุณทำสิ่งนี้:

List<string> strings = new List<string>().WithItems("Yes");

หรือ

List<string> strings = new List<string>().WithItems("Yes", "No", "Maybe So");

อัปเดต

ตอนนี้คุณสามารถใช้ list initializers:

var strings = new List<string> { "This", "That", "The Other" };

ดูhttp://msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx


อาจเป็นเพราะ C # รุ่นใหม่กว่าตั้งแต่ปี 2009 แต่ฉันคิดว่าnew List<string> {"Yes"}จะดีกว่า ... ?
ErikE

@ErikE ตามเอกสารของ Microsoft ( msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx ) สิ่งนี้ได้รับการสนับสนุนใน Visual Studio 2008 ฉันจำไม่ได้ว่าย้อนกลับไปเพื่อพูดอย่างชัดเจนหาก ฉันซับซ้อนมากเกินไปในเวลานั้น กำลังอัปเดต
Michael Meadows

7

อีกวิธีหนึ่งที่พบใน "C # /. Net Little Wonders" (น่าเสียดายที่ไซต์นี้ไม่มีอยู่แล้ว):

Enumerable.Repeat("value",1).ToList()

สับสน แต่ฉลาด
PRMan

4

สำหรับรายการเดียวที่สามารถระบุได้ใน java จะเป็น Collections.singleton ("string");

ใน c # สิ่งนี้จะมีประสิทธิภาพมากกว่ารายการใหม่:

public class SingleEnumerator<T> : IEnumerable<T>
{
    private readonly T m_Value;

    public SingleEnumerator(T value)
    {
        m_Value = value;
    }

    public IEnumerator<T> GetEnumerator()
    {
        yield return m_Value;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        yield return m_Value;
    }
}

แต่มีวิธีที่ง่ายกว่านี้โดยใช้กรอบหรือไม่?


นั่นเป็นคำตอบที่ดีที่สุดในความคิดของฉัน เป็นรูปแบบทั่วไปที่จะมีรายการรายการเดียวเพื่อลดขนาดการจัดสรร หากคุณกำลังมองหาทางลัดอยู่แล้วคุณอาจรวมความสะดวกเข้ากับสิ่งดีๆ
Alexander Oh


2

ฉันมีฟังก์ชั่นเล็ก ๆ น้อย ๆ นี้:

public static class CoreUtil
{    
    public static IEnumerable<T> ToEnumerable<T>(params T[] items)
    {
        return items;
    }
}

เนื่องจากไม่ได้กำหนดประเภทการส่งคืนคอนกรีตจึงเป็นเรื่องทั่วไปที่ฉันใช้มันทั่วทุกที่ รหัสของคุณจะมีลักษณะดังนี้

CoreUtil.ToEnumerable("title").ToList();

แต่แน่นอนมันยังช่วยให้

CoreUtil.ToEnumerable("title1", "title2", "title3").ToArray();

ฉันมักจะใช้มันเมื่อฉันต้องต่อท้าย / เพิ่มหนึ่งรายการในผลลัพธ์ของคำสั่ง LINQ ตัวอย่างเช่นการเพิ่มรายการว่างในรายการการเลือก:

CoreUtil.ToEnumerable("").Concat(context.TrialTypes.Select(t => t.Name))

ประหยัดงบToList()และAddงบน้อย

(คำตอบช้า แต่ฉันสะดุดกับคนแก่คนนี้และคิดว่านี่น่าจะเป็นประโยชน์)



2

ได้รับแรงบันดาลใจจากคำตอบอื่น ๆ (และฉันสามารถเลือกได้ทุกเมื่อที่ต้องการ!) แต่ด้วยการตั้งชื่อ / สไตล์ที่สอดคล้องกับ F # (ซึ่งมีsingletonฟังก์ชันมาตรฐานต่อโครงสร้างข้อมูล *):

namespace System.Collections.Generic
{
    public static class List
    {
        public static List<T> Singleton<T>(T value) => new List<T>(1) { value };
    }
}

* ยกเว้นResizeArrayตัวของมันเองดังนั้นคำถามนี้ :)


ในทางปฏิบัติผมจริงชื่อมันCreateเพื่อให้สอดคล้องกับผู้ช่วยเหลืออื่น ๆ ที่ฉันกำหนดเช่นTuple.Create, Lazy.Create[2], LazyTask.Createฯลฯ :

namespace System.Collections.Generic
{
    public static class List
    {
        public static List<T> Create<T>(T value) => new List<T>(1) { value };
    }
}

[2]

namespace System
{
    public static class Lazy
    {
        public static Lazy<T> Create<T>(Func<T> factory) => new Lazy<T>(factory);
    }
}

ขอบคุณ! ทางออกของฉันเช่นกัน. สิ่งที่สอง: (1) การนำรายการของคุณไปใช้งานไม่ได้เป็นแบบสาธารณะดังนั้นจึงไม่สามารถใช้ภายนอกแอสเซมบลีการประกาศได้และ (2) จุดประสงค์ของการบรรจุสิ่งเหล่านี้ลงในเนมสเปซระบบคืออะไร?
Codure

@StephenRobinson เหตุผลในการใส่Lazyส่วนขยายSystemคือLazyตัวมันเองอยู่ในSystem[และด้วยเหตุนี้จึงCreateจะปรากฏในรายการ compleiton โดยไม่มีusing] ไม่มีอะไรจะได้รับจากการบังคับให้ผู้คนopenใช้เนมสเปซที่แตกต่างกัน? การทำให้สิ่งอื่นเป็นส่วนตัวไม่ได้มีเจตนา; คงที่
Ruben Bartelink

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.