Làm cách nào để tạo kiểu trả về của một phương thức chung?


165

Có cách nào để làm cho phương thức này chung chung để tôi có thể trả về một chuỗi, bool, int hoặc double không? Ngay bây giờ, nó trả về một chuỗi, nhưng nếu nó có thể tìm thấy "true" hoặc "false" làm giá trị cấu hình, thì tôi muốn trả về một bool chẳng hạn.

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

Có cách nào để bạn biết mỗi loại cài đặt là gì không?
thecoshman

2
Tôi nghĩ rằng câu hỏi bạn thực sự muốn hỏi là "Làm cách nào để cấu hình ứng dụng của tôi được gõ mạnh?" Tuy nhiên, đã quá lâu kể từ khi tôi làm việc với nó để viết một câu trả lời thích hợp.
Simon

Yah, lý tưởng nhất là tôi không muốn truyền loại này vào phương thức. Tôi chỉ có 4 loại tôi đã đề cập. Vì vậy, nếu "true" / "false" được đặt, tôi muốn hàm này trả về một boolean (mà không cần truyền nó vào phương thức), tôi có thể kết hợp int và double thành gấp đôi và mọi thứ khác phải là một chuỗi. Những gì đã được trả lời sẽ hoạt động tốt, nhưng tôi cần phải vượt qua loại này mỗi lần, điều này có thể tốt.
MacGyver

3
Nhận xét của bạn có vẻ như bạn đang yêu cầu một phương thức sẽ trả về một bool được gõ mạnh (hoặc chuỗi, hoặc int hoặc những gì có) trong thời gian chạy dựa trên dữ liệu thực tế được lấy cho khóa tên cài đặt. C # sẽ không làm điều đó cho bạn; không có cách nào bạn có thể biết loại giá trị đó tại thời điểm biên dịch. Nói cách khác, đó là kiểu gõ động chứ không phải kiểu gõ tĩnh. C # có thể làm điều đó cho bạn nếu bạn sử dụng dynamictừ khóa. Có một chi phí hiệu năng cho điều đó, nhưng để đọc một tệp cấu hình, chi phí hiệu năng gần như chắc chắn không đáng kể.
phoog

Câu trả lời:


353

Bạn cần làm cho nó trở thành một phương thức chung, như thế này:

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

Nhưng người gọi sẽ phải chỉ định loại họ mong đợi. Sau đó, bạn có thể sử dụng Convert.ChangeType, giả sử rằng tất cả các loại có liên quan đều được hỗ trợ:

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

Tôi không hoàn toàn tin rằng tất cả điều này là một ý tưởng tốt, nhớ bạn ...


21
/ * mã để chuyển đổi cài đặt thành T ... * / và ở đây theo toàn bộ cuốn tiểu thuyết :)
Adrian Iftode

1
Điều này sẽ không yêu cầu bạn biết loại cài đặt bạn muốn nhận, có thể không thể.
thecoshman

2
@thecoshman: Nó sẽ như vậy, nhưng nếu bạn không làm thì bạn sẽ làm gì với giá trị trả về?
George Duckett

5
Trong khi câu trả lời này là tất nhiên đúng, và như bạn lưu ý đáp ứng yêu cầu của OP, nó có thể là đáng nhắc đến rằng cách tiếp cận cũ của phương pháp riêng biệt ( ConfigSettingString, ConfigSettingBool, vv) có lợi thế của các cơ quan phương pháp đó sẽ ngắn hơn, rõ ràng hơn, và tập trung tốt hơn .
phoog

4
Nếu điều này không được khuyến nghị thì mục đích của các loại trả lại chung là gì?
bulkalex

29

Bạn có thể sử dụng Convert.ChangeType():

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

13

Có nhiều cách để làm điều này (được liệt kê theo mức độ ưu tiên, cụ thể cho vấn đề của OP)

  1. Tùy chọn 1: Cách tiếp cận thẳng - Tạo nhiều chức năng cho từng loại bạn mong đợi thay vì có một chức năng chung.

    public static bool ConfigSettingInt(string settingName)
    {  
         return Convert.ToBoolean(ConfigurationManager.AppSettings[settingName]);
    }
  2. Tùy chọn 2: Khi bạn không muốn sử dụng các phương thức chuyển đổi ưa thích - Truyền giá trị cho đối tượng và sau đó đến loại chung.

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

    Lưu ý - Điều này sẽ gây ra lỗi nếu diễn viên không hợp lệ (trường hợp của bạn). Tôi không khuyên bạn nên làm điều này nếu bạn không chắc chắn về kiểu truyền, thay vào đó là tùy chọn 3.

  3. Tùy chọn 3: Chung với loại an toàn - Tạo chức năng chung để xử lý chuyển đổi loại.

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

    Lưu ý - T là loại dự kiến, lưu ý ràng buộc ở đây (loại U phải có khả năng IConvertible để cứu chúng tôi khỏi các lỗi)


4
Tại sao làm cho tùy chọn thứ ba chung chung trong U? Không có điểm nào để làm như vậy, và nó làm cho phương thức khó gọi hơn. Chỉ cần chấp nhận IConvertiblethay thế. Tôi không nghĩ nó có giá trị bao gồm tùy chọn thứ hai cho câu hỏi này vì nó không trả lời câu hỏi đang được hỏi. Có lẽ bạn cũng nên đổi tên phương thức trong tùy chọn đầu tiên ...
Jon Skeet

7

Bạn phải chuyển đổi loại giá trị trả về của phương thức thành loại Chung mà bạn chuyển sang phương thức trong khi gọi.

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

Bạn cần vượt qua một loại có thể truyền được cho giá trị bạn trả về thông qua phương thức đó.

Nếu bạn muốn trả về một giá trị không thể phân loại thành loại chung mà bạn vượt qua, bạn có thể phải thay đổi mã hoặc đảm bảo rằng bạn chuyển một loại có thể chuyển thành giá trị trả về của phương thức. Vì vậy, cách tiếp cận này không được đề xuất.


Spot on - đối với tôi dòng cuối cùng return (T)Convert.ChangeType(number, typeof(T));chính xác là những gì tôi đã thiếu - chúc mừng
Greg Trevellick 2/2/19

1

Tạo một hàm và đưa ra tham số put như kiểu chung.

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

Điều này thực sự khá thông minh cho một vài trường hợp sử dụng. Giống như kéo dữ liệu ra khỏi cơ sở dữ liệu. Bạn biết bạn sẽ nhận được một danh sách dữ liệu loại T. Phương thức tải chỉ không biết bạn muốn loại T nào NGAY BÂY GIỜ. Vì vậy, chỉ cần chuyển một Danh sách mới <WantedObject> cho điều này và phương thức có thể thực hiện công việc đó và điền vào danh sách trước khi trả lại. Đẹp!
Marco Heumann

0

Vui lòng thử mã dưới đây:

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

Tôi đã thực hiện điều này trong suốt mã của mình và muốn có một cách để đưa nó vào một phương thức. Tôi muốn chia sẻ điều này ở đây vì tôi không phải sử dụng Convert.ChangeType cho giá trị trả về của mình. Đây có thể không phải là một thực hành tốt nhất nhưng nó đã làm việc cho tôi. Phương thức này lấy một mảng kiểu chung và một giá trị để thêm vào cuối mảng. Sau đó, mảng được sao chép với giá trị đầu tiên bị tước và giá trị được đưa vào phương thức được thêm vào cuối mảng. Điều cuối cùng là tôi trả về mảng chung.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.