下面我将对这五个主题分别进行详细的介绍和示例说明。
C#值类型和引用类型
在C#中,变量可以分为值类型和引用类型。值类型存储的是实际的值,而引用类型存储的是内存地址。值类型包括整型、浮点型、字符型、布尔型等,而引用类型包括类、数组、委托等等。
在实际开发中,我们通常需要对值类型和引用类型进行区分。下面是一个简单的示例代码,展示了值类型和引用类型的区别:
int i = 10; // 值类型变量
int j = i; // 变量的值被赋值给新变量
j = 20; // 修改新变量的值,不影响原变量的值
Console.WriteLine("i = {0}, j = {1}", i, j); // 输出:i = 10, j = 20
List<int> list1 = new List<int>() { 1, 2, 3 }; // 引用类型变量,创建一个整型列表
List<int> list2 = list1; // 将列表的引用赋值给新变量
list2.Add(4); // 向新列表中添加一个元素
Console.WriteLine("list1 = {0}, list2 = {1}", string.Join(",", list1), string.Join(",", list2)); // 输出:list1 = 1,2,3,4, list2 = 1,2,3,4
从上述示例代码可知,值类型的变量在被赋值时是进行拷贝的,而引用类型的变量在被赋值时是共享内存地址的。因此,在修改引用类型变量时,会影响所有指向该内存地址的变量。
泛型
泛型是C#中非常重要的一个概念。它将类型参数化,使得类、方法和接口可以用于多种不同类型的数据。泛型代码具有高复用性,可以大幅减少代码的重复编写。
下面是一个简单的示例代码,展示了泛型类型的使用:
public class GenericStack<T>
{
private List<T> _items = new List<T>();
public void Push(T item)
{
_items.Add(item);
}
public T Pop()
{
if (_items.Count == 0)
{
throw new InvalidOperationException("The stack is empty.");
}
T item = _items[_items.Count - 1];
_items.RemoveAt(_items.Count - 1);
return item;
}
}
GenericStack<int> stack = new GenericStack<int>();
stack.Push(1);
stack.Push(2);
stack.Push(3);
Console.WriteLine(stack.Pop()); // 输出:3
Console.WriteLine(stack.Pop()); // 输出:2
Console.WriteLine(stack.Pop()); // 输出:1
在上述示例代码中,我们定义了一个泛型类型 GenericStack<T>
,它实现了栈的基本操作 Push
和 Pop
。通过在声明变量时指定类型参数,可以创建一个 int
类型的栈。
集合
C#中的集合是一组有序的、通常是可变的元素的数据结构。它们是用来存储和操作数据的常见方法,比如列表、集合、散列表等。
下面是一个简单的示例代码,展示了使用集合来操作数据的方法:
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; // 创建整型列表
numbers.Add(6); // 向列表中添加一个元素
Console.WriteLine(numbers.Count); // 输出:6
HashSet<int> set = new HashSet<int>() { 1, 2, 3, 4, 5 }; // 创建哈希集合
set.Add(6); // 向哈希集合中添加一个元素
Console.WriteLine(set.Count); // 输出:6
Dictionary<string, int> dict = new Dictionary<string, int>();
// 创建字典
dict.Add("apple", 1);
dict.Add("orange", 2);
dict.Add("banana", 3);
Console.WriteLine(dict["orange"]); // 输出:2
在上述示例代码中,我们使用了三种不同的集合类型:列表 List
、哈希集合 HashSet
和字典 Dictionary
。它们分别提供了不同的操作方法,可以满足不同的使用场景。
调用函数的表达式树实践
表达式树是C#中非常有用的一个特性。它允许我们以编程方式创建和操作代码中的表达式。通过表达式树,我们可以将函数调用封装到一个表达式中,然后在运行时动态调用该函数。
下面是一个简单的示例代码,展示了使用表达式树调用函数的方法:
// 声明一个带参数的函数
int Add(int a, int b)
{
return a + b;
}
// 创建表达式
ParameterExpression x = Expression.Parameter(typeof(int), "x");
ParameterExpression y = Expression.Parameter(typeof(int), "y");
BinaryExpression body = Expression.Add(x, y);
Expression<Func<int, int, int>> add = Expression.Lambda<Func<int, int, int>>(body, x, y);
// 编译表达式并调用函数
int result = add.Compile()(1, 2);
Console.WriteLine(result); // 输出:3
在上述示例代码中,我们定义了一个 Add
函数,它接受两个整型参数并返回它们的和。然后,我们通过表达式树创建了一个调用该函数的表达式,编译表达式并最终调用该函数。
另一个示例代码(来源自微软官方文档),使用表达式树实现了一个比较器,用于将一个字符串列表按长度排序:
List<string> list = new List<string> { "apple", "banana", "cherry", "date" };
// 创建表达式
ParameterExpression parameter = Expression.Parameter(typeof(string), "x");
Expression<Func<string, int>> selector = Expression.Lambda<Func<string, int>>(
Expression.Property(parameter, "Length"), parameter);
var comparerExpr = typeof(Comparer<>)
.MakeGenericType(typeof(int))
.GetProperty("Default", BindingFlags.Static | BindingFlags.Public)
.GetMethod
.ReturnType
.GetMethod("Create", new[] { typeof(Func<,>).MakeGenericType(typeof(int), typeof(int)) })
.Invoke(null, new object[] { selector });
// 使用表达式排序列表
list.Sort((IComparer<string>)comparerExpr);
Console.WriteLine(string.Join(",", list)); // 输出:date,apple,cherry,banana
在上述示例代码中,我们通过表达式树创建了一个比较器,并将该比较器用于对字符串列表按长度排序。虽然这个过程比较复杂,但它展示了表达式树的一个非常有用的功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#值类型、引用类型、泛型、集合、调用函数的表达式树实践 - Python技术站