C#类继承自泛型集合
继承自泛型字典的例子
这段代码定义了一个多层嵌套的字典结构,旨在组织和存储复杂的层级数据
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.");
}
}
}