C# 是否支持 "Generic inheritance" 和 how/why?

Does C# support "Generic inheritance" and how/why?

我想声明类似这样的内容:

public class ImpostorClassWithAddedNotificationSupport<T> : T, ICustomTypeProvider, INotifyPropertyChanged where T : class

但是我收到这个错误:

CS0689: Cannot derive from 'T' because it is a type parameter

我想用我的 class 向属性动态添加新行为(覆盖基础 class 属性)。我的 class 中的每个 属性 都会调用 base class 属性 然后向其添加通知。我还会添加更多功能(方法)。这样,一切都可以在设计中正常工作,但对派生 class 具有额外的功能。一种模仿(冒名顶替者)的方式来添加更多功能。

有没有办法动态覆盖类型以添加​​功能(例如通知等功能)?如果是,如何?如果不是,为什么?

我的初衷是:

我尝试做一个模拟任何我想编辑的对象的 FakeObject。它会动态地创建它模仿的任何对象的所有属性。然后我可以编辑那个“FakeObject”,如果我想取消,我刷新那个 fakeObject 并且我的原始对象从未被修改(就像任何对话框上的“取消”)。在“确定”时,它将对原始对象应用更改。它已经适用于 PropertyGrid,因为 PropertyGrid 使用后面的反射来发现和 read/write 属性。但我想在设计时将我的 class 与 WPF 和 WinUI 一起使用。通知部分只是它附带的奖励。否则我必须编写一个“复制构造函数”或任何类似的复制机制,而且我必须在每个 classes 上实现 INotifyPropertyChanged。我宁愿保留我的 classes “Plain” - POCO。如果我能够按预期编写代码,我会保存所有这些。

一问才明白

实际上是不可能的。我应该向微软寻求新功能。

不,这不能以这种方式实现,因为编译器错误指示。基本上,泛型让您可以围绕该泛型类型编写 class 而无需对其了解太多,除了您对其施加的约束,例如 where T : class。所以对于编译器来说它有太多的未知数。请记住,泛型 class 可以使用不在其程序集中的事物的泛型类型,例如 List,其中 List 在 MS 程序集中,而 Foo 在您的自定义程序集中。基础 classes 在编译时需要在派生 class 的可见程序集中。

您可以查看 MS 文档 here or a MS blog post here

不过,问得好。这些类型的问题确实有助于充实对 C# 和 OO 的理解及其能力和局限性。

这在 .Net 中根本不可能。

因为您不知道 T 是什么,所以您无法重写任何方法,也无法对其调用任何方法。如果您添加一个接口约束来为您提供这种可能性,您可以从该接口继承并创建一个常规装饰器。

所以我假设您需要某种模板来包装您要装饰的类型中的每个方法,以提供诸如日志记录之类的东西。而且这个概念可能需要对 IL 格式和运行时进行重大更改才能支持。

一种可能的解决方法是使用反射在运行时动态发出新类型。另一种可能是使用注释重写程序集中的 IL 代码,以向方法添加附加功能。我相信这是 PostSharp.

使用的方法

所以你真正想要的是这样的:

MyClass x = new AddNotificationSupport<MyClass>();

AddNotificationSupport<>实现了装饰器或代理(一直没搞懂两者的区别)。我认为你最好的方法是 Castle.DynamicProxy project. Here is a great tutorial to learn how it works and what you can do with it: https://kozmic.net/dynamic-proxy-tutorial/

更新:
在您对问题进行编辑之后。您可以 Mixin 一些 ChangeTracker class 与原始 class。然后实现一个拦截器来装饰需要的方法和属性。 ChangeTracker class 应该“记住”在代理上应用的所有更改,并提供通过调用 Cancel 扩展方法恢复它们的能力。

此代码可以帮助您开始:

public static T AsTrackable<T>(this T target)
    where T : class
{
    if (target == null)
    {
        return null;
    }

    if (target is ITrackableObject)
    {
        return target;
    }

    var options = new ProxyGenerationOptions { Hook = new TrackableHook() };
    options.AddMixinInstance(new TrackableObject());
    var interceptor = new TrackSettersInterceptor();

    var result = (T)_proxyGenerator.CreateClassProxyWithTarget(
        typeof(T),
        new[] { typeof(ITrackableObject) },
        target,
        options,
        interceptor);

    return result;
}

您需要实施 TrackableObjectTrackableHookTrackSettersInterceptor