ฉันจะสร้างประเภทคืนค่าของวิธีการทั่วไปได้อย่างไร


166

มีวิธีที่จะทำให้วิธีนี้เป็นแบบทั่วไปเพื่อให้ฉันสามารถส่งกลับสตริง, บูล, int หรือสองครั้ง? ตอนนี้มันส่งคืนสตริง แต่ถ้าสามารถหาค่า "จริง" หรือ "เท็จ" เป็นค่ากำหนดได้ฉันต้องการคืนค่าบูลเช่น

    public static string ConfigSetting(string settingName)
    {  
         return ConfigurationManager.AppSettings[settingName];
    }

มีวิธีให้คุณรู้ว่าการตั้งค่าแต่ละประเภทคืออะไร
thecoshman

2
ฉันคิดว่าคำถามที่คุณต้องการถามจริงๆคือ "ฉันจะตั้งค่าแอปพลิเคชันของฉันได้อย่างไร?" มันนานเกินไปแล้วที่ฉันทำงานกับมันเพื่อเขียนคำตอบที่เหมาะสม
Simon

ย่ะฉันไม่ต้องการให้มันผ่านเข้าไปในวิธีการ ฉันแค่จะมี 4 ประเภทที่ฉันพูดถึง ดังนั้นหากตั้งค่า "true" / "false" ฉันต้องการให้ฟังก์ชันนี้คืนค่าบูลีน (โดยไม่จำเป็นต้องผ่านมันเข้าไปในเมธอด) ฉันอาจรวมค่า int และ double เข้าด้วยกันเป็นสองเท่าและทุกอย่างอื่นควรเป็นสตริง สิ่งที่ตอบแล้วจะใช้ได้ดี แต่ฉันต้องผ่านประเภทนี้ทุกครั้งซึ่งอาจจะดี
MacGyver

3
ความคิดเห็นของคุณดูเหมือนว่าคุณกำลังขอวิธีที่จะส่งกลับค่าบูล (หรือสตริงหรือ int หรือสิ่งที่คุณมี) ที่รันไทม์ตามข้อมูลที่เรียกจริงสำหรับคีย์ชื่อการตั้งค่า C # จะไม่ทำเพื่อคุณ ไม่มีวิธีที่คุณสามารถทราบชนิดของค่านั้นในเวลารวบรวม กล่าวอีกนัยหนึ่งนั่นคือการพิมพ์แบบไดนามิกไม่ใช่การพิมพ์แบบคงที่ C # สามารถทำได้สำหรับคุณหากคุณใช้dynamicคำหลัก มีค่าประสิทธิภาพสำหรับเรื่องนั้น แต่สำหรับการอ่านไฟล์กำหนดค่าประสิทธิภาพนั้นแทบไม่มีนัยสำคัญแน่นอน
phoog

คำตอบ:


354

คุณต้องทำให้มันเป็นวิธีการทั่วไปเช่นนี้:

public static T ConfigSetting<T>(string settingName)
{  
    return /* code to convert the setting to T... */
}

แต่ผู้โทรจะต้องระบุประเภทที่พวกเขาคาดหวัง จากนั้นคุณสามารถใช้Convert.ChangeTypeสมมติว่ารองรับประเภทที่เกี่ยวข้องทั้งหมด:

public static T ConfigSetting<T>(string settingName)
{  
    object value = ConfigurationManager.AppSettings[settingName];
    return (T) Convert.ChangeType(value, typeof(T));
}

ฉันไม่เชื่อว่าทั้งหมดนี้เป็นความคิดที่ดีใจคุณ ...


21
/ * รหัสการแปลงการตั้งค่าเป็น T ... * / และที่นี่ต่อไปนี้นวนิยายทั้ง :)
เอเดรีย Iftode

1
สิ่งนี้จะไม่ทำให้คุณต้องรู้ประเภทของการตั้งค่าที่คุณต้องการซึ่งอาจเป็นไปไม่ได้
thecoshman

2
@thecoshman: มันจะ แต่ถ้าคุณไม่ได้แล้วสิ่งที่คุณจะทำอย่างไรกับค่าที่ส่งคืน?
George Duckett

5
ในขณะที่คำตอบนี้เป็นของที่ถูกต้องแน่นอนและเป็นคุณทราบตอบสนองคำขอของ OP ก็อาจจะมีมูลค่าการกล่าวขวัญว่าวิธีเก่าวิธีการแยกต่างหาก ( ConfigSettingString, ConfigSettingBoolฯลฯ ) มีความได้เปรียบของร่างกายวิธีการที่จะสั้นลงชัดเจนและมุ่งเน้นไปที่ดีกว่า .
phoog

4
หากไม่แนะนำให้ทำเช่นนี้แล้ววัตถุประสงค์ของประเภทการคืนสินค้าทั่วไปคืออะไร
bobbyalex


13

มีหลายวิธีในการทำเช่นนี้ (แสดงตามลำดับความสำคัญเฉพาะปัญหาของ OP)

  1. ตัวเลือกที่ 1: วิธีการแบบตรง - สร้างฟังก์ชั่นหลายอย่างสำหรับแต่ละประเภทที่คุณคาดหวังแทนที่จะมีหนึ่งฟังก์ชั่นทั่วไป

    public static bool ConfigSettingInt(string settingName)
    {  
         return Convert.ToBoolean(ConfigurationManager.AppSettings[settingName]);
    }
  2. ตัวเลือกที่ 2: เมื่อคุณไม่ต้องการใช้วิธีการแปลงที่แปลกใหม่ - ส่งค่าเป็นวัตถุและประเภททั่วไป

    public static T ConfigSetting<T>(string settingName)
    {  
         return (T)(object)ConfigurationManager.AppSettings[settingName];
    }

    หมายเหตุ -สิ่งนี้จะทำให้เกิดข้อผิดพลาดหากนักแสดงไม่ถูกต้อง (กรณีของคุณ) ฉันจะไม่แนะนำให้ทำเช่นนี้หากคุณไม่แน่ใจเกี่ยวกับการคัดเลือกนักแสดงแทนที่จะเลือกตัวเลือก 3

  3. ตัวเลือก 3: Generic with safety safety - สร้างฟังก์ชันทั่วไปเพื่อจัดการการแปลงชนิด

    public static T ConvertValue<T,U>(U value) where U : IConvertible
    {
        return (T)Convert.ChangeType(value, typeof(T));
    } 

    หมายเหตุ - T เป็นประเภทที่คาดไว้ให้สังเกตข้อ จำกัด ที่นี่ (ประเภทของ U จะต้องเป็น IConvertible เพื่อช่วยเราจากข้อผิดพลาด)


4
ทำให้ตัวเลือกที่สามในทั่วไปทำไมU? ไม่มีจุดทำเช่นนั้นและทำให้วิธีการโทรยากขึ้น เพียงยอมรับIConvertibleแทน ฉันไม่คิดว่ามันคุ้มค่ารวมถึงตัวเลือกที่สองสำหรับคำถามนี้เนื่องจากไม่ตอบคำถามที่ถาม คุณควรเปลี่ยนชื่อเมธอดในตัวเลือกแรก ...
Jon Skeet

7

คุณต้องแปลงประเภทของค่าตอบแทนของวิธีเป็นประเภททั่วไปที่คุณส่งไปยังวิธีการในระหว่างการโทร

    public static T values<T>()
    {
        Random random = new Random();
        int number = random.Next(1, 4);
        return (T)Convert.ChangeType(number, typeof(T));
    }

คุณต้องผ่านประเภทที่สามารถพิมพ์ได้อย่างมีคุณค่าสำหรับค่าที่คุณส่งคืนผ่านวิธีการนั้น

หากคุณต้องการส่งคืนค่าที่ไม่พิมพ์ casteable ให้กับประเภททั่วไปที่คุณผ่านคุณอาจต้องเปลี่ยนรหัสหรือตรวจสอบให้แน่ใจว่าคุณผ่านประเภทที่สามารถนำกลับมาใช้กับค่าที่ส่งคืนของเมธอดได้ ดังนั้นวิธีนี้จึงไม่แนะนำอีก


จุดบน - สำหรับฉันบรรทัดสุดท้ายreturn (T)Convert.ChangeType(number, typeof(T));คือสิ่งที่ฉันหายไป - ไชโย
เกร็ก Trevellick

1

สร้างฟังก์ชั่นและส่งออกพารามิเตอร์ใส่เป็นประเภททั่วไป

 public static T some_function<T>(T out_put_object /*declare as Output object*/)
    {
        return out_put_object;
    }

อันนี้เป็นสมาร์ทสวยสำหรับกรณีใช้ไม่กี่ ชอบดึงข้อมูลออกจากฐานข้อมูล คุณรู้ว่าคุณจะได้รับรายการข้อมูลประเภท T วิธีการโหลดไม่ทราบประเภทของ T ที่คุณต้องการในตอนนี้ ดังนั้นเพียงแค่ส่ง List ใหม่ <WantedObject> ไปที่สิ่งนี้และวิธีการสามารถทำได้และเติมรายการก่อนที่จะส่งคืน ดี!
Marco Heumann

0

กรุณาลองรหัสด้านล่าง:

public T? GetParsedOrDefaultValue<T>(string valueToParse) where T : struct, IComparable
{
 if(string.EmptyOrNull(valueToParse))return null;
  try
  {
     // return parsed value
     return (T) Convert.ChangeType(valueToParse, typeof(T));
  }
  catch(Exception)
  {
   //default as null value
   return null;
  }
 return null;
}

-1
 private static T[] prepareArray<T>(T[] arrayToCopy, T value)
    {
        Array.Copy(arrayToCopy, 1, arrayToCopy, 0, arrayToCopy.Length - 1);
        arrayToCopy[arrayToCopy.Length - 1] = value;
        return (T[])arrayToCopy;
    }

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

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