c# 9.0 记录 - 反射和泛型约束

kof*_*fus 14 c# c#-9.0 record-classes

关于新记录功能的两个问题:

  1. 如何使用反射识别记录?看 [here][1] 也许有一种方法可以检测到,EqualityContract但我不确定这是否可行?

  2. 是否可以有一个泛型约束,即泛型类型是记录?也就是说,是否可以使用约束指示类型参数 T 必须是记录类?

Ili*_*hev 12

  1. 如何使用反射识别记录?

如果您尝试使用记录类,sharplab.io您将看到记录类是实现IEquatable<T>接口并包含用于比较和克隆记录类实例的附加成员的常用类。没有特殊属性表明该类是record class.

所以我想没有办法使用反射来确定一个类是否是一个记录类。

这里,也许有一种方法可以检测到, EqualityContract但我不确定这是否可行?

可以使用反射来确定类是否具有此类属性,但这并不能 100% 保证具有此类属性的类是记录类。


  1. 是否可以有一个泛型约束,即泛型类型是记录?也就是说,是否可以使用约束指示类型参数 T 必须是记录类?

这不可能。

  1. 记录提案页面不包含有关指定泛型类型参数T必须是记录类的任何信息。
  2. 如果您在page 上阅读此评论下的讨论,Champion records您将了解到无法指定类似where T : recordin 的内容C# 9。此外,还计划消除C# 10. 这样记录的功能with也将可用于类。添加record约束将使这个目标无法实现。


Yai*_*adt 8

作为“黑客”,所有记录都有一个<Clone>$您可以查找的合成方法。由于您不能在 C# 中编写具有该名称的方法,因此<Clone>$保证具有成员的类是C# 9的记录。

然而,不能保证这种情况会继续下去。例如,在 C# 10.0 中,某些记录可能没有<Clone>$成员,或者某些非记录有成员。

public static bool IsRecord(Type type) => type.GetMethod("<Clone>$") != null;
Run Code Online (Sandbox Code Playgroud)

  • 我不知道为什么要这样做,但理论上使用 `Reflection.Emit` 你可以让某人创建一个具有 `&lt;Clone&gt;$` 方法的对象,但它不是记录 (2认同)

Rhe*_*xis 6

正如其他人所提到的,不可能写

private void MyFunc<T>(T t) where T : record {...}
Run Code Online (Sandbox Code Playgroud)

但是,您可以创建一个记录,然后您创建的每个记录类型都继承自该记录。这几乎可以实现您的要求,尽管我不知道我对此有何感觉......

public abstract record RecordMarker;
public record MyRecord : RecordMarker;
public void MyFunc<T>(T t) where T : RecordMarker
{
}
Run Code Online (Sandbox Code Playgroud)

有了这个,您只能传入记录类型,因为类不能从记录继承。

MyFunc(new MyRecord()); // Works
MyFunc(new MyClass());  // Compiler Error
Run Code Online (Sandbox Code Playgroud)


kof*_*fus 4

如何使用反射识别记录?

正如此处此处指出的

不仅没有官方的方法可以做到这一点,而且它明确违背了该功能的设计。记录的目的是,希望通过 C# 10,我们能够达到将类设为记录纯粹是一种方便的选择,并且该功能的所有其他部分都可以通过某种形式的语法来实现。将类型从记录更改为类不应该是重大更改,我们甚至可以想象 IDE 重构可以自动将类型移至记录语法或从记录语法移出类型,而无需客户注意。对于 C# 9,有些地方我们没有完全实现这一目标,但这就是目标。

尽管存在上述情况,但在某些情况下检查记录仍然很有用。一些检测 ATM 工作记录的黑客方法是:

  1. 检查是否存在EqualityContract具有该属性的CompilerGenerated属性
isRecord = ((TypeInfo)t).DeclaredProperties.Where(x => x.Name == "EqualityContract").FirstOrDefault()?.GetMethod?.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) is object;
Run Code Online (Sandbox Code Playgroud)
  1. 检查<Clone>$@Yair Halberstadt 指出的成员
isRecord = t.GetMethod("<Clone>$") is object;
Run Code Online (Sandbox Code Playgroud)

或两者的组合

是否可以有一个泛型约束,即泛型类型是一条记录?