如何在不知道底层记录类型的情况下在接口上使用关键字“with”?

问题描述 投票:0回答:1

在 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
执行相同的操作,而这正是我在用例中所需要的。

c# interface c#-9.0 c#-record-type
1个回答
0
投票

这目前在 .NET 8 (C# 11) 中似乎不可能实现。

根据定义,with语法仅对基于值的structsrecords有效,不适用于引用的类 基于。 “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();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.