将其转换为泛型类型而不欺骗编译器

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

考虑这个简化的类层次结构:

public interface IProcessor
{
  Task<TProcessor> Run<TProcessor>() where TProcessor : IProcessor;
}


public abstract class Processor : IProcessor
{

  public async Task<TProcessor> Run<TProcessor>() where TProcessor : IProcessor
  {
    await DoWork();
    return (TProcessor)(object)this;  // works, but yuck
    //return (TProcessor)this;        // error: "Cannot convert type 'Processor' to 'TProcessor'"
  }

  protected abstract Task DoWork();

}


public sealed class FooProcessor : Processor
{
  protected override Task DoWork() => Task.CompletedTask;
}

(TProcessor)(object)this
技巧有效,但是是一个丑陋的编译器黑客。

我可以修改此代码以依赖编译时检查吗?

c# generics casting .net-7.0
1个回答
0
投票

如果您有另一个继承自

Processor
的类,例如
BarProcessor
,则可能会出现运行时错误。然后
BarProcessor p = new FooProcessor().Run<BarProcessor>();
将编译,但在运行时会失败。

C# 不支持这样的“self”类型(例如参见 https://github.com/dotnet/csharplang/issues/5413),但是可以通过将类型参数从方法移至类型。这限制了类实现中出现错误的可能性,并减少了在调用站点指定类型参数的需要。

例如:

public interface IProcessor<TProcessor> where TProcessor : IProcessor<TProcessor>
{
    Task<TProcessor> Run();
}

public abstract class Processor<TProcessor> : IProcessor<TProcessor>
    where TProcessor : Processor<TProcessor>
{
    public async Task<TProcessor> Run()
    {
      await DoWork();
      return (TProcessor)this;
    }

    protected abstract Task DoWork();
}

public sealed class FooProcessor : Processor<FooProcessor>
{
    protected override Task DoWork() => Task.CompletedTask;
}

public sealed class BarProcessor : Processor<BarProcessor>
{
    protected override Task DoWork() => Task.CompletedTask;
}

现在

Run
的调用者不能指定错误的类型参数(因为没有任何类型参数),但
FooProcessor
仍然可以错误地从
Processor<BarProcessor>
继承。此外,接口
IProcessor<TProcessor>
现在显然只用作约束 (
where T: IProcessor<T>
),而不是用作类型。

请注意,

FooProcessor
BarProcessor
已密封。允许从
Processor<TProcessor>
子类继承将要求该子类是通用的,例如
public abstract class SpecialProcessor<TProcessor> : Processor<TProcessor> where TProcessor : SpecialProcessor<TProcessor>

© www.soinside.com 2019 - 2024. All rights reserved.