关于新记录功能有两个问题:
如何使用反射识别记录?在这里查看[1],也许可以检测
EqualityContract
,但我不确定是否应该采用这种方式?是否可能有一个通用的约束条件,即通用类型是记录?也就是说,如果可以使用约束指示类型参数T必须是记录类吗?
关于新记录功能有两个问题:
如何使用反射识别记录?在这里查看[1],也许可以检测EqualityContract
,但我不确定是否应该采用这种方式?
是否可能有一个通用的约束条件,即通用类型是记录?也就是说,如果可以使用约束指示类型参数T必须是记录类吗?
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
sharplab.io
中尝试记录类,您会发现记录类是实现IEquatable<T>
接口的普通类,并包含用于比较和克隆记录类实例的附加成员。没有特殊的属性表明该类是record class
。因此,我认为使用反射无法确定类是否为记录类。EqualityContract
,但我不确定这是否是正确的方法?where T:record
的内容。此外,计划消除记录和类之间任何有意义的语义差异,在C#10中,记录功能(如with
)也将对类可用。添加record
约束将使这个目标无法实现。csharplang
开发团队有关于添加问题 #1 和 #2 中所提到的功能支持的额外信息(或见解)。因此,我认为最好直接向 csharplang
团队在 C# 的 Github 仓库 上提出这个问题。 - Iliar Turdushev作为一个“hack”,所有的记录都有一个合成方法<Clone>$
,你可以查找它。由于你无法在C#中写一个这样的名称的方法,一个带有<Clone>$
成员的类被保证是一个记录,至少在C# 9中是这样。
然而,不能保证这种情况将会持续下去。例如,在C# 10.0中,一些记录可能没有<Clone>$
成员,或者一些非记录类型可能会有。
public static bool IsRecord(Type type) => type.GetMethod("<Clone>$") != null;
Reflection.Emit
,你可以让别人创建一个具有 <Clone>$
方法且不是记录的对象。 - nalka尽管如上所述,仍然存在一些场景需要检查记录。目前可用的一些hack方式来检测记录包括:目前没有官方方法来实现这一点,这甚至是该功能设计上明确反对的。对于记录的意图是,希望通过某种形式的语法实现每个记录功能,以便在 C# 10 中将类设置为记录仅是一种方便的选择。不应该通过将类型从记录更改为类来破坏其他部分的记录特性,我们甚至可以想象IDE重构可以自动移动类型到和从记录语法中而没有客户端察觉到。对于C# 9,有一些地方我们并未完全实现这一点,但这是目标。
CompilerGenerated
属性的EqualityContract
属性isRecord = ((TypeInfo)t).DeclaredProperties.Where(x => x.Name == "EqualityContract").FirstOrDefault()?.GetMethod?.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) is object;
<Clone>$
成员,正如@Yair Halberstadt所指出的。isRecord = t.GetMethod("<Clone>$") is object;
或两者的组合
是否可能有一个泛型约束,使泛型类型成为一条记录?
不可能
<Clone>$
是MVC绑定检测记录需要构建的方式。https://github.com/dotnet/aspnetcore/blob/c925f99cddac0df90ed0bc4a07ecda6b054a0b02/src/Mvc/Mvc.Core/src/ModelBinding/Metadata/DefaultBindingMetadataProvider.cs#L101 - Jeremy LakemanisRecord = t.GetMethod("<Clone>$") is object; ==> isRecord = t.GetMethod("<Clone>$") is not null;