在 C# 中,有没有一种方法可以在接口上使用
with
关键字,而不知道对象的类型(或基类型)?
我正在想象类似以下伪代码中的
DoSomething
方法(这不是有效的 c#)。代码 DoSomething
将作用于所有实现 ISomeRecord
的记录。
DoSomething2
方法可以编译,但仅适用于SomeRecord
类型的记录,不适用于SomeRecord
以外类型的记录。
public interface ISomeRecord
{
bool SomeProp { get; }
}
public record SomeRecord : ISomeRecord
{
public bool SomeProp { get; init; }
}
public class SomeUtil
{
public ISomeRecord DoSomething(ISomeRecord rec)
{
return ( rec as record ) with { SomeProp = false };
}
public ISomeRecord DoSomething2(ISomeRecord rec)
{
return ( rec as SomeRecord ) with { SomeProp = false };
}
public ISomeRecord DoSomething3<T>(T rec) where T : struct, ISomeRecord
{
return rec with { SomeProp = false };
}
}
顺便说一句,在 C# 10 中(在撰写本文时处于预览状态),我注意到
DoSomething3
可以编译。 C# 10 引入了 record structs
和 record classes
。后者是默认值。看来我所追求的对于 record struct
对象是可能的,但对于 record class
对象是不可能的。换句话说,在示例中,无法使用 DoSomething3
作为参数来调用 SomeRecord
,除非将 SomeRecord
更改为 record struct
。
我没有找到一种方法可以对
record class
执行相同的操作,而这正是我在用例中所需要的。
这目前在 .NET 8 (C# 11) 中似乎不可能实现。
根据定义,with语法仅对基于值的structs和records有效,不适用于引用的类 基于。 “with” 应该是快速克隆的方法 实例的 value,如果您想对类执行相同的操作,则必须使用 IClonable 接口并显式/手动管理克隆实例的创建方式。
因为在 interface 上使用 with 的这种区别会导致歧义,这可能解释了为什么他们决定省略对接口的支持,因为从技术上讲,接口可以代表同一事物。
我通过添加一个如何使用抽象类实现最接近的事情的示例来扩展@Zero的评论:
public abstract record SomeRecordBase
{
public abstract bool SomeProp { get; init; }
}
public record SomeRecord : SomeRecordBase
{
public override bool SomeProp { get; init; }
}
// as an extension method
public static class SomeUtilExtension
{
public static SomeRecordBase DoSomething(this SomeRecordBase rec)
{
return rec with { SomeProp = false };
}
}
// as a utility class
public class SomeUtil
{
public SomeRecordBase DoSomething(SomeRecordBase rec)
{
return rec with { SomeProp = false };
}
}
//TESTER CODE
public static class MainProgram
{
public static void Main()
{
SomeRecord rec = new SomeRecord { SomeProp = true };
SomeRecordBase recBase = rec.DoSomething();
}
}