C#泛型中的new()约束

本文深入探讨了C#编程中new约束的概念,解释了其在创建对象、调用构造函数以及作为修饰符隐藏继承成员时的作用,并通过示例展示了如何在泛型类中正确使用new约束。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

new() 约束的意思是
传入的类参数 必须具有可访问的无参数(或默认)构造函数。
就是说传入的这个类必定能通过new()来进行实例化
 
这样用的好处
如果类 T 有new约束 你就可以在泛型类定义里使用new T()方法 否则就不能使用

//
1)用于创建对象和调用构造函数。例如:
Class1 o = new Class1();
new 运算符还用于调用值类型的默认构造函数。例如:
int i = new int();
在上一个语句中,i 初始化为 0,它是 int 类型的默认值。该语句的效果等同于:
int i = 0;
//
2)在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。隐藏继承的成员意味着该成员的派生版本将替换基类版本。在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。使用 new 显式隐藏成员会取消此警告,并记录代之以派生版本这一事实。
若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并使用 new 修饰符修饰该成员。例如:
public class BaseC
{
public int x;
public void Invoke() {}
}
public class DerivedC : BaseC
{
new public void Invoke() {}
}
在此示例中,DerivedC.Invoke 隐藏了 BaseC.Invoke。字段 x 不受影响,因为它没有被类似名称的字段隐藏。
通过继承隐藏名称采用下列形式之一:
引入类或结构中的常数、指定、属性或类型隐藏具有相同名称的所有基类成员。
引入类或结构中的方法隐藏基类中具有相同名称的属性、字段和类型。同时也隐藏具有相同签名的所有基类方法。
引入类或结构中的索引器将隐藏具有相同名称的所有基类索引器。
对同一成员同时使用 new 和 override 是错误的,因为这两个修饰符在含义上相互排斥。使用 new 会用同样的名称创建一个新成员并使原始成员变为隐藏的,而 override 则扩展继承成员的实现。
在不隐藏继承成员的声明中使用 new 修饰符将会生成警告。
示例
在该例中,基类 BaseC 和派生类 DerivedC 使用相同的字段名 x,从而隐藏了继承字段的值。该示例演示了 new 修饰符的用法。另外还演示了如何使用完全限定名访问基类的隐藏成员。
复制代码
// cs_modifier_new.cs
// The new modifier.
using System;
public class BaseC
{
public static int x = 55;
public static int y = 22;
}
public class DerivedC : BaseC
{
// Hide field 'x'
new public static int x = 100;
static void Main()
{
// Display the new value of x:
Console.WriteLine(x);
// Display the hidden value of x:
Console.WriteLine(BaseC.x);
// Display the unhidden member y:
Console.WriteLine(y);
}
}
作者添加:
输出结果为:
100
55
22
//
3)new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。当泛型类创建类型的新实例时,将此约束应用于类型参数,如下面的示例所示:
class ItemFactory<T> where T : new()
{
public T GetNewItem()
{
return new T();
}
}
当与其他约束一起使用时,new() 约束必须最后指定:
复制代码
using System;
public class ItemFactory<T>
where T : IComparable, new()
{
}
//到此结束
1本文由jvdlvcjpyf贡献
本文由iamzhangyu贡献
//
1)用于创建对象和调用构造函数。例如:
Class1 o = new Class1();
new 运算符还用于调用值类型的默认构造函数。例如:
int i = new int();
在上一个语句中,i 初始化为 0,它是 int 类型的默认值。该语句的效果等同于:
int i = 0;
//
2)在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。隐藏继承的成员意味着该成员的派生版本将替换基类版本。在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。使用 new 显式隐藏成员会取消此警告,并记录代之以派生版本这一事实。
若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并使用 new 修饰符修饰该成员。例如:
public class BaseC
{
public int x;
public void Invoke() {}
}
public class DerivedC : BaseC
{
new public void Invoke() {}
}
在此示例中,DerivedC.Invoke 隐藏了 BaseC.Invoke。字段 x 不受影响,因为它没有被类似名称的字段隐藏。
通过继承隐藏名称采用下列形式之一:
引入类或结构中的常数、指定、属性或类型隐藏具有相同名称的所有基类成员。
引入类或结构中的方法隐藏基类中具有相同名称的属性、字段和类型。同时也隐藏具有相同签名的所有基类方法。
引入类或结构中的索引器将隐藏具有相同名称的所有基类索引器。
对同一成员同时使用 new 和 override 是错误的,因为这两个修饰符在含义上相互排斥。使用 new 会用同样的名称创建一个新成员并使原始成员变为隐藏的,而 override 则扩展继承成员的实现。
在不隐藏继承成员的声明中使用 new 修饰符将会生成警告。
示例
在该例中,基类 BaseC 和派生类 DerivedC 使用相同的字段名 x,从而隐藏了继承字段的值。该示例演示了 new 修饰符的用法。另外还演示了如何使用完全限定名访问基类的隐藏成员。
复制代码
// cs_modifier_new.cs
// The new modifier.
using System;
public class BaseC
{
public static int x = 55;
public static int y = 22;
}
public class DerivedC : BaseC
{
// Hide field 'x'
new public static int x = 100;
static void Main()
{
// Display the new value of x:
Console.WriteLine(x);
// Display the hidden value of x:
Console.WriteLine(BaseC.x);
// Display the unhidden member y:
Console.WriteLine(y);
}
}
作者添加:
输出结果为:
100
55
22
//
3)new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。当泛型类创建类型的新实例时,将此约束应用于类型参数,如下面的示例所示:
class ItemFactory<T> where T : new()
{
public T GetNewItem()
{
return new T();
}
}
当与其他约束一起使用时,new() 约束必须最后指定:
复制代码
using System;
public class ItemFactory<T>
where T : IComparable, new()
{
}
//到此结束
<think>我们正在讨论C#参数约束。根据引用,我们可以总结如下: 1. 引用[1]展示了在成员函数中使用参数作为约束的例子,其中`U`必须继承自`T`。 2. 引用[2]说明类参数可以在类定义中用作约束,并且必须在尖括号中声明所有类参数。 3. 引用[3]提到C#7.3以后允许使用枚举类作为约束。 4. 引用[4]强调了约束的重要性,以避免运行时错误。 用户的问题:了解C#参数约束的条件和用法。 回答结构: 1. 解释什么是约束及其作用。 2. 列出常见的约束并举例说明。 3. 说明多个约束的用法。 4. 提及一些特殊的约束(如枚举、委托等)以及版本支持情况。 5. 使用示例代码展示用法。 注意:所有代码示例中的参数和约束需要正确使用LaTeX格式(行内用$...$,独立成段用$$...$$)。但由于这里主要是代码块,我们使用代码块标记。 同时,按照要求生成相关问题。</think>### C# 参数约束详解 #### 一、约束的作用与语法 约束通过`where`关键字限制可传入的类参数,确保类安全性和功能可用性。基本语法: ```csharp class MyClass<T> where T : constraint_type { ... } ``` #### 二、主要约束及用法 1. **基类约束** 要求类参数必须继承指定基类: ```csharp class Repository<T> where T : EntityBase { public void Save(T entity) { ... } } ``` 2. **接口约束** 要求实现特定接口,支持多接口约束: ```csharp void Log<T>(T data) where T : ILogger, ISerializable { ... } ``` 3. **值类约束** (`struct`) 限制为值类(枚举、结构体等): ```csharp T CreateDefault<T>() where T : struct => default; ``` 4. **引用类约束** (`class`) 限制为引用类: ```csharp class Cache<T> where T : class { ... } ``` 5. **无参构造函数约束** (`new()`) 要求类必须有公共无参构造函数: ```csharp T CreateInstance<T>() where T : new() => new T(); ``` 6. **枚举约束** (C# 7.3+) 限制为枚举类: ```csharp string GetName<T>(T value) where T : Enum => Enum.GetName(typeof(T), value); ``` 7. **类参数约束** 约束参数之间的关系: ```csharp class Converter<T, U> where U : T { ... } // U必须继承T ``` #### 三、多约束组合 可叠加多个约束,顺序为:主约束 → 接口约束 → 构造函数约束: ```csharp T Process<T>(T obj) where T : BaseClass, IDisposable, new() { using (obj) { return new T(); } } ``` #### 四、特殊约束 - **非空约束** (C# 8.0+, `notnull`): `where T : notnull` 排除可空类 - **委托/元组约束** (C# 7.3+): `where T : Delegate` 或 `where T : ValueTuple` #### 五、使用场景 1. **类安全** 避免向方法传入不支持操作的类[^4]。 2. **访问特定成员** 如约束为`IComparable`后可调用`CompareTo()`方法。 3. **设计模式应用** 工厂模式中确保可实例化(`new()`约束)[^2]。 > 示例:带约束集合 ```csharp public class SmartList<T> where T : IEntity, new() { public void AddItem() => items.Add(new T()); private List<T> items = new(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值