繼承自泛型字典的例子
這段程式碼定義了一個多層巢狀的字典結構,旨在組織和儲存複雜的層級資料
using System;
using System.Threading.Tasks;
class Contract : Dictionary<string, Dictionary<string, Dictionary<string, string>>>
{
private readonly string type = "autodesk.data:exchange.contract.dynamo-1.0.0";
public Contract()
{
var contractContent = new Dictionary<string, Dictionary<string, string>>
{
{ "contract", new Dictionary<string, string>() }
};
Add(type, contractContent);
}
}
class Program
{
static void Main()
{
// Create an instance of Contract
var contract = new Contract();
// Access the outer dictionary using the predefined type key
var typeKey = "autodesk.data:exchange.contract.dynamo-1.0.0";
// Check if the key exists and add data
if (contract.TryGetValue(typeKey, out var contractContent))
{
// Access the inner dictionary with the key "contract"
if (contractContent.TryGetValue("contract", out var innerDictionary))
{
// Add key-value pairs to the innermost dictionary
innerDictionary["key1"] = "value1";
innerDictionary["key2"] = "value2";
// Retrieve and display values
Console.WriteLine(innerDictionary["key1"]); // Outputs: value1
Console.WriteLine(innerDictionary["key2"]); // Outputs: value2
}
}
}
}
value1
value2
再看一個Dynamo專案例項,這段程式碼的目的是建立一個巢狀字典結構,用於儲存有關二進位制引用元件的屬性資料。使用介面IPropertySet作為多型機制的基礎。透過巢狀字典結構實現多層次資料的組織和訪問。提供靈活的屬性管理,適合複雜物件的屬性儲存場景
using System;
using System.Threading.Tasks;
class BinaryReferenceComponent : Dictionary<string, Dictionary<string, IPropertySet>>
{
private string objectId = "autodesk.data:binary.reference.component-1.0.0";
public string ObjectId { get { return objectId; } }
public BinaryReferenceComponent(string binaryId)
{
var propertyDictionary = new Dictionary<string, IPropertySet>();
propertyDictionary.Add("String", new StringPropertySet(binaryId));
propertyDictionary.Add("Uint32", new IntPropertySet());
this.Add("binary_reference", propertyDictionary);
}
}
class StringPropertySet : IPropertySet
{
public string Id { get; set; }
public string Revision { get; set; }
public StringPropertySet(string binaryId, string revision = "v0")
{
Id = binaryId;
Revision = revision;
}
}
class IntPropertySet : IPropertySet
{
public int End { get; set; }
public int Start { get; set; }
public IntPropertySet(int start = 0, int end = 8710)
{
End = end;
Start = start;
}
}
interface IPropertySet { }
class Program
{
static void Main()
{
// Create an instance of BinaryReferenceComponent with a binaryId
var binaryReference = new BinaryReferenceComponent("exampleBinaryId");
// Access ObjectId
Console.WriteLine($"ObjectId: {binaryReference.ObjectId}");
// Access properties of the component
if (binaryReference.TryGetValue("binary_reference", out var propertySet))
{
if (propertySet.TryGetValue("String", out var stringProperty))
{
var stringProp = stringProperty as StringPropertySet;
Console.WriteLine($"StringProperty Id: {stringProp.Id}, Revision: {stringProp.Revision}");
}
if (propertySet.TryGetValue("Uint32", out var intProperty))
{
var intProp = intProperty as IntPropertySet;
Console.WriteLine($"IntProperty Start: {intProp.Start}, End: {intProp.End}");
}
}
}
}
ObjectId: autodesk.data:binary.reference.component-1.0.0
StringProperty Id: exampleBinaryId, Revision: v0
IntProperty Start: 0, End: 8710
繼承多種集合型別
在C#中,除了泛型字典外,你還可以繼承其他集合型別,例如:
- List
:可以建立自定義列表類,但不常見,建議使用組合 - HashSet
:用於無重複元素集合,但繼承並不常見 - Queue
和Stack :分別用於佇列和棧的實現 - Collection
和ReadOnlyCollection :更適合繼承,提供了更好的方法定製化能力
示例:繼承 Collection
程式碼說明
-
CustomCollection<T>
類:- 繼承自
Collection<T>
- 重寫了
InsertItem
方法,新增插入前後的自定義行為 - 定義了一個
ItemAdded
事件,當新專案新增時觸發
- 繼承自
-
Main
函式:- 建立
CustomCollection<string>
的例項 - 訂閱
ItemAdded
事件,輸出新增的項資訊 - 新增幾個專案並顯示集合中的所有專案
- 建立
關鍵點
- 事件處理: 使用事件機制通知項的新增
- 自定義行為: 透過重寫方法實現特定邏輯
- 靈活性:
CustomCollection<T>
可以用於任何型別的集合
using System;
using System.Collections.ObjectModel;
class CustomCollection<T> : Collection<T>
{
// Event triggered when an item is added
public event Action<T> ItemAdded;
// Custom implementation of InsertItem
protected override void InsertItem(int index, T item)
{
// Add custom behavior before inserting
Console.WriteLine($"Inserting item at index {index}: {item}");
base.InsertItem(index, item);
// Trigger the event after inserting
ItemAdded?.Invoke(item);
}
// Method to display all items
public void DisplayItems()
{
Console.WriteLine("Current items in collection:");
foreach (var item in this)
{
Console.WriteLine(item);
}
}
}
class Program
{
static void Main()
{
// Create an instance of CustomCollection
var collection = new CustomCollection<string>();
// Subscribe to the ItemAdded event
collection.ItemAdded += item => Console.WriteLine($"Item added: {item}");
// Add items to the collection
collection.Add("Item1");
collection.Add("Item2");
collection.Add("Item3");
// Display all items in the collection
collection.DisplayItems();
}
}
執行結果:
Inserting item at index 0: Item1
Item added: Item1
Inserting item at index 1: Item2
Item added: Item2
Inserting item at index 2: Item3
Item added: Item3
Current items in collection:
Item1
Item2
Item3
注意
在C#中,類繼承自泛型字典並不常見。以下是一些原因和建議:
原因
- 違背封裝原則:直接繼承集合類可能導致外部程式碼直接操作集合內部結構,違背封裝原則
- 集合行為的複雜性:集合類提供的行為可能不完全適合自定義類的需求,可能需要重寫大量方法。繼承集合類可能引入維護複雜性
組合優於繼承:常用的設計模式是組合,即在類內部包含一個集合,而不是繼承它
建議
- 使用組合:在類中定義一個集合欄位,並透過方法或屬性操作它。這可以更好地控制訪問和行為
擴充套件方法:如果需要對集合進行特定操作,可以使用擴充套件方法來增強其功能,而不是繼承
將前面的一個繼承的例子改為使用組合,執行結果不變
using System;
using System.Collections.Generic;
interface IPropertySet { }
class StringPropertySet : IPropertySet
{
public string Id { get; set; }
public string Revision { get; set; }
public StringPropertySet(string binaryId, string revision = "v0")
{
Id = binaryId;
Revision = revision;
}
}
class IntPropertySet : IPropertySet
{
public int End { get; set; }
public int Start { get; set; }
public IntPropertySet(int start = 0, int end = 8710)
{
End = end;
Start = start;
}
}
class BinaryReferenceComponent
{
private Dictionary<string, Dictionary<string, IPropertySet>> properties = new();
public string ObjectId { get; } = "autodesk.data:binary.reference.component-1.0.0";
public BinaryReferenceComponent(string binaryId)
{
var propertyDictionary = new Dictionary<string, IPropertySet>
{
{ "String", new StringPropertySet(binaryId) },
{ "Uint32", new IntPropertySet() }
};
properties.Add("binary_reference", propertyDictionary);
}
public Dictionary<string, IPropertySet> GetProperties(string key)
{
properties.TryGetValue(key, out var result);
return result;
}
}
class Program
{
static void Main()
{
// Create an instance of BinaryReferenceComponent
var binaryReference = new BinaryReferenceComponent("exampleBinaryId");
// Access ObjectId
Console.WriteLine($"ObjectId: {binaryReference.ObjectId}");
// Retrieve properties using GetProperties method
var properties = binaryReference.GetProperties("binary_reference");
if (properties != null)
{
if (properties.TryGetValue("String", out var stringProperty))
{
var stringProp = stringProperty as StringPropertySet;
Console.WriteLine($"StringProperty Id: {stringProp.Id}, Revision: {stringProp.Revision}");
}
if (properties.TryGetValue("Uint32", out var intProperty))
{
var intProp = intProperty as IntPropertySet;
Console.WriteLine($"IntProperty Start: {intProp.Start}, End: {intProp.End}");
}
}
else
{
Console.WriteLine("No properties found for the given key.");
}
}
}
參考
- https://github.com/DynamoDS/Dynamo.git