c# 9.0 记录 - 反射和通用约束
c# 9.0 records - reflection and generic constraints
关于新记录功能的两个问题:
如何使用反射识别记录?看[这里][1]也许那里
是一种检测 EqualityContract
的方法,但我不确定这是否可行?
是否可以有一个泛型约束,泛型类型是一个记录?也就是说,如果可以使用约束来指示类型参数 T 必须是记录 class ?
- How do I recognize a record using reflection ?
如果你尝试在 sharplab.io
中记录 classes 你会看到记录 classes 是通常的 classes 实现 IEquatable<T>
接口和包含用于比较和克隆记录 class 实例的其他成员。没有特殊属性表明 class 是 record class
.
所以我想没有办法使用反射来确定class是否是一条记录class。
looking here maybe there is a way to detect the
EqualityContract
but I am not sure if that is the way to go ?
如果一个class有这样的属性,可以使用反射来确定,但这不是100%保证class有这样的属性一条记录 class.
- Is it possible to have a generic constraint that a generic type is a
record ? that is if it is possible to indicate that type parameter T
must be a record class using a constraint ?
不可能。
- Records proposal page 不包含任何有关指定泛型类型参数
T
必须是记录 class. 的信息
- 如果您在
Champion records
页面阅读此 comment 下的讨论,您将了解到无法在 C# 9
中指定类似 where T : record
的内容。此外,还有计划消除记录与 C# 10
中的 class 之间任何有意义的语义差异。因此 with
等记录的功能也可用于 classes。添加 record
约束将使该目标无法实现。
作为一个'hack',所有记录都有一个合成方法<Clone>$
,你可以找找。由于您不能在 C# 中编写具有该名称的方法,因此具有 <Clone>$
成员的 class 保证是 C# 9 的记录。
但是不能保证这种情况会继续存在。例如,在 C# 10.0 中,某些记录可能没有 <Clone>$
成员,或者某些 non-records 可能有。
public static bool IsRecord(Type type) => type.GetMethod("<Clone>$") != null;
How do I recognize a record using reflection ?
There is not only not an official way to do this, it is explicitly against the design of the feature. The intent for records is that, hopefully with C# 10, we'll get to a point where making a class a record is purely a convenience choice, and that every other part of the feature will be achievable through some form of syntax. It should not be a breaking change to change a type from a record to a class, and we even imagine that an IDE refactoring could automatically move a type to and from record syntax without clients noticing. For C# 9 there are some places where we didn't quite achieve this, but that's the goal.
尽管有上述情况,在某些情况下检查记录对我们还是很有用的。检测 ATM 工作记录的一些骇人听闻的方法是:
- 检查是否有
EqualityContract
属性 具有 CompilerGenerated
属性
isRecord = ((TypeInfo)t).DeclaredProperties.Where(x => x.Name == "EqualityContract").FirstOrDefault()?.GetMethod?.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) is object;
- 检查@Yair Halberstadt 指出的
<Clone>$
成员
isRecord = t.GetMethod("<Clone>$") is object;
或两者的结合
Is it possible to have a generic constraint that a generic type is a record ?
没有
正如大家所说,写不出来
private void MyFunc<T>(T t) where T : record {...}
但是您可以创建一个记录,然后您创建的每个记录类型都继承自该记录。这几乎可以实现您的要求,尽管我不知道我对此有何感想...
public abstract record RecordMarker;
public record MyRecord : RecordMarker;
public void MyFunc<T>(T t) where T : RecordMarker
{
}
由于类无法从记录继承,因此您只能传入记录类型。
MyFunc(new MyRecord()); // Works
MyFunc(new MyClass()); // Compiler Error
isRecord = t.GetMethod("<Clone>$") is object; ==> isRecord = t.GetMethod("<Clone>$") is not null;
尽管这里有一些答案,但似乎是一个非常合理的问题。事实上,记录只是 class 的语法糖,可以通过多种其他方式创建。
一个选项是创建一个空的标记记录库 class 或接口,即使它是空的,并向其添加约束。这将实现所需的约束。
如果您从这个 classes 继承所有您希望包含在约束中的 class,那么它将正常工作。
关于新记录功能的两个问题:
如何使用反射识别记录?看[这里][1]也许那里 是一种检测
EqualityContract
的方法,但我不确定这是否可行?是否可以有一个泛型约束,泛型类型是一个记录?也就是说,如果可以使用约束来指示类型参数 T 必须是记录 class ?
- How do I recognize a record using reflection ?
如果你尝试在 sharplab.io
中记录 classes 你会看到记录 classes 是通常的 classes 实现 IEquatable<T>
接口和包含用于比较和克隆记录 class 实例的其他成员。没有特殊属性表明 class 是 record class
.
所以我想没有办法使用反射来确定class是否是一条记录class。
looking here maybe there is a way to detect the
EqualityContract
but I am not sure if that is the way to go ?
如果一个class有这样的属性,可以使用反射来确定,但这不是100%保证class有这样的属性一条记录 class.
- Is it possible to have a generic constraint that a generic type is a record ? that is if it is possible to indicate that type parameter T must be a record class using a constraint ?
不可能。
- Records proposal page 不包含任何有关指定泛型类型参数
T
必须是记录 class. 的信息
- 如果您在
Champion records
页面阅读此 comment 下的讨论,您将了解到无法在C# 9
中指定类似where T : record
的内容。此外,还有计划消除记录与C# 10
中的 class 之间任何有意义的语义差异。因此with
等记录的功能也可用于 classes。添加record
约束将使该目标无法实现。
作为一个'hack',所有记录都有一个合成方法<Clone>$
,你可以找找。由于您不能在 C# 中编写具有该名称的方法,因此具有 <Clone>$
成员的 class 保证是 C# 9 的记录。
但是不能保证这种情况会继续存在。例如,在 C# 10.0 中,某些记录可能没有 <Clone>$
成员,或者某些 non-records 可能有。
public static bool IsRecord(Type type) => type.GetMethod("<Clone>$") != null;
How do I recognize a record using reflection ?
There is not only not an official way to do this, it is explicitly against the design of the feature. The intent for records is that, hopefully with C# 10, we'll get to a point where making a class a record is purely a convenience choice, and that every other part of the feature will be achievable through some form of syntax. It should not be a breaking change to change a type from a record to a class, and we even imagine that an IDE refactoring could automatically move a type to and from record syntax without clients noticing. For C# 9 there are some places where we didn't quite achieve this, but that's the goal.
尽管有上述情况,在某些情况下检查记录对我们还是很有用的。检测 ATM 工作记录的一些骇人听闻的方法是:
- 检查是否有
EqualityContract
属性 具有CompilerGenerated
属性
isRecord = ((TypeInfo)t).DeclaredProperties.Where(x => x.Name == "EqualityContract").FirstOrDefault()?.GetMethod?.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) is object;
- 检查@Yair Halberstadt 指出的
<Clone>$
成员
isRecord = t.GetMethod("<Clone>$") is object;
或两者的结合
Is it possible to have a generic constraint that a generic type is a record ?
没有
正如大家所说,写不出来
private void MyFunc<T>(T t) where T : record {...}
但是您可以创建一个记录,然后您创建的每个记录类型都继承自该记录。这几乎可以实现您的要求,尽管我不知道我对此有何感想...
public abstract record RecordMarker;
public record MyRecord : RecordMarker;
public void MyFunc<T>(T t) where T : RecordMarker
{
}
由于类无法从记录继承,因此您只能传入记录类型。
MyFunc(new MyRecord()); // Works
MyFunc(new MyClass()); // Compiler Error
isRecord = t.GetMethod("<Clone>$") is object; ==> isRecord = t.GetMethod("<Clone>$") is not null;
尽管这里有一些答案,但似乎是一个非常合理的问题。事实上,记录只是 class 的语法糖,可以通过多种其他方式创建。
一个选项是创建一个空的标记记录库 class 或接口,即使它是空的,并向其添加约束。这将实现所需的约束。
如果您从这个 classes 继承所有您希望包含在约束中的 class,那么它将正常工作。