在 C# 中,存儲不同類型的數據有多種方式,具體選擇取決于你的需求(類型安全、性能、靈活性等)。以下是常見的解決方案及其適用場景:
1. 使用 object
類型(裝箱 / 拆箱)
將所有數據轉換為基類 object
,利用 C# 的多態性存儲任意類型。
List<object> mixedList = new List<object>();
mixedList.Add(123); ? ? ? ? ? ?// int → 裝箱為object
mixedList.Add("Hello"); ? ? ? ?// string(引用類型無需裝箱)
mixedList.Add(new DateTime()); // DateTime → 裝箱為object
?
// 訪問時需手動拆箱(可能引發InvalidCastException)
int num = (int)mixedList[0]; ? // 拆箱
string str = (string)mixedList[1];
優點:簡單直接,無需額外類型定義。
缺點:
裝箱 / 拆箱開銷:值類型(如
int
,DateTime
)頻繁轉換會降低性能。類型不安全:運行時可能拋出
InvalidCastException
。
2. 使用泛型集合 List<dynamic>
dynamic 關鍵字在運行時動態解析類型,避免編譯時類型檢查。List<dynamic> dynamicList = new List<dynamic>();
dynamicList.Add(123); ? ? ? ?// 無需裝箱
dynamicList.Add("Hello");
dynamicList.Add(new { Name = "Alice" }); // 匿名類型也可存儲
?
// 訪問時無需顯式轉換
int num = dynamicList[0]; ? ?// 動態類型解析
string str = dynamicList[1];
優點:
無需裝箱拆箱(值類型以原始類型存儲)。
支持匿名類型等復雜結構。
缺點:
運行時類型風險:若類型不匹配會在運行時拋出異常。
性能開銷:動態解析比靜態類型稍慢。
3. 使用自定義類 / 結構體(推薦方案)
public class MixedData
{public int Id { get; set; }public string Name { get; set; }public DateTime BirthDate { get; set; }
}
?
// 使用方式
List<MixedData> dataList = new List<MixedData>();
dataList.Add(new MixedData { Id = 1, Name = "Alice", BirthDate = DateTime.Now
});
定義一個包含所需字段的類,每個字段使用明確的類型。
public class MixedData
{public int Id { get; set; }public string Name { get; set; }public DateTime BirthDate { get; set; }
}
?
// 使用方式
List<MixedData> dataList = new List<MixedData>();
dataList.Add(new MixedData { Id = 1, Name = "Alice", BirthDate = DateTime.Now
});
優點:
類型安全:編譯時檢查類型。
可讀性高:字段含義明確。
性能最優:無需裝箱拆箱。
缺點:需提前定義類型,不夠靈活。
4. 使用 Tuple
或 ValueTuple
適合臨時存儲少量不同類型的數據。// Tuple(舊版,需通過Item1、Item2訪問)
var tupleList = new List<Tuple<int, string>>();
tupleList.Add(Tuple.Create(1, "Alice"));
?
// ValueTuple(C# 7.0+,推薦,支持命名元素)
var valueTupleList = new List<(int Id, string Name)>();
valueTupleList.Add((1, "Alice"));
?
// 訪問方式
int id = valueTupleList[0].Id;
string name = valueTupleList[0].Name;
優點:簡潔,無需額外類定義。
缺點:
元素數量有限(最多 8 個)。
不適合復雜或大量數據。
5. 使用 Dictionary<string, object>
以鍵值對形式存儲不同類型的值,類似動態對象。
var dict = new Dictionary<string, object>();
dict["Id"] = 123;
dict["Name"] = "Alice";
dict["IsActive"] = true;
?
// 訪問時需轉換類型
int id = (int)dict["Id"];
bool isActive = (bool)dict["IsActive"];
優點:靈活,可動態添加 / 刪除鍵值對。
缺點:
類型不安全,需手動轉換。
鍵名硬編碼,易出錯。
6. 使用接口或抽象類(面向對象設計)
定義公共接口,讓不同類型實現該接口。
public interface IDataItem { }
?
public class Person : IDataItem
{public string Name { get; set; }
}
?
public class Product : IDataItem
{public decimal Price { get; set; }
}
?
// 使用方式
List<IDataItem> items = new List<IDataItem>();
items.Add(new Person { Name = "Alice" });
items.Add(new Product { Price = 9.99m });
?
// 通過模式匹配訪問
foreach (var item in items)
{if (item is Person person)Console.WriteLine(person.Name);else if (item is Product product)Console.WriteLine(product.Price);
}
優點:
類型安全,符合面向對象原則。
可擴展,易于添加新類型。
缺點:需設計接口和繼承體系,復雜度較高。
7. 使用 ExpandoObject
(動態對象)
System.Dynamic.ExpandoObject
是動態類型的字典,支持運行時添加屬性。
dynamic person = new ExpandoObject();
person.Name = "Alice";
person.Age = 30;
?
// 直接訪問屬性(無需轉換)
Console.WriteLine(person.Name); // "Alice"
優點:
語法簡潔,像普通對象一樣訪問屬性。
無需提前定義類型。
缺點:
編譯時無類型檢查,易出錯。
性能略低于靜態類型。
7.
ArrayList
(非泛型,不推薦)特點:
來自
System.Collections
命名空間,可存儲任意類型(實際存為object
)。動態擴容,但存在裝箱 / 拆箱開銷和類型安全問題。
示例:
using System.Collections; ? ArrayList list = new ArrayList(); list.Add("張三"); ? ?// string → object(裝箱) list.Add(10); ? ? ? ?// int → object(裝箱) list.Add(2.2); ? ? ? // double → object(裝箱) ? // 訪問時需手動拆箱,可能引發InvalidCastException int num = (int)list[1]; // 拆箱
方案 | 裝箱開銷 | 類型安全 | 性能(相對) |
---|---|---|---|
List<object> | 有 | 否 | 低 |
List<dynamic> | 無 | 否 | 中 |
自定義類 / 結構體 | 無 | 是 | 高 |
Dictionary<string, object> | 有 | 否 | 中 |
ExpandoObject | 無 | 否 | 中低 |
ArrayList | 有 | 否 | 低 |