首页 > 解决方案 > 如何仅将特定的通用对象传递给方法,该方法将第一个 T 作为派生 T

问题描述

考虑这个代码示例:

我们在解决方案中对我们的 UI 系统进行了抽象:

public abstract class Frame: IFrame {...}
public abstract class Frame<T> : Frame, IFrame<T> {...}
public abstract class Modal:Frame {...}
public abstract class Modal<T>:Modal,IFrame<T> {...}
...

新的模态类可以声明为:

public class MyModal : Modal<T> {...}

其中 T - 数据结构(或类)用于实现具有某些值的模态。

为了预初始化、调整和显示这些 UI,我们使用静态类,其中包含以下方法:

public static T ShowFrame<T>(params) where T : class, IFrame
public static T ShowFrame<T,TK>(TK data, params) where T : class, IFrame<TK>

所以现在,为了显示 MyModal,我们只需调用:

A.ShowFrame<MyModal>(...);

并使用数据:

A.ShowFrame<MyModal, MyModalData>(new MyModalData(...));

问题是,我们如何将类型数据作为TK传递?我们可以这样写:A.ShowFrame<MyModal>(new AnyClassInSolution(...)); 这是不正确的用例。

在当前系统中用户可以传递不正确的数据,这不会做任何事情,但是我们要避免这种用例并防止长写,例如:

A.ShowFrame<MyModal>(new MyModalData(...));

代替

A.ShowFrame<MyModal, MyModalData>(new MyModalData(...));

并且也TK只能是 T 的数据类型。

我正在考虑制作一个带有对“A”的回调的包装器,它将派生出流畅的 api 和 split 的功能Show<TFrame>以及Set(data) 任何其他想法,关于如何在一种方法中直接实现它?

编辑:

需要注意的重要一点是,我们尝试使用 IData (或类似的)接口来导出所有数据,而public static T ShowFrame<T,TK>(TK data, params) where T : class, IFrame<TK>不是public static T ShowFrame<T>(IData data, params) where T : class, IFrame

这解决了可用性问题:没问题A.ShowFrame<MyModal>(new MyModalData(...));

但是这里的问题——我们要支持structclass数据输入。(请参阅结构接口装箱/拆箱问题)并且未解决不正确的数据用例。

标签: c#genericsinheritanceabstract-class

解决方案


引入第二个IFrame后代并将数据绑定和非数据绑定类明确分离到两个不同的继承树中可能会提供额外的安全级别。考虑一下:

public interface IFrameNoData : IFrame { … }
public interface IFrame<T> : IFrame { … }

public abstract class FrameNoData : IFrameNoData { … }
public abstract class ModalNoData : FrameNoData {...}
… other abstract classes remain the same …

public class MyModalNoData : MyModal { … }

然后ShowFrame重载将清楚地区分数据绑定和非数据绑定后代:

public static T ShowFrame<T>() where T : class, IFrameNoData
public static T ShowFrame<T,TK>(TK data) where T : class, IFrame<TK>

像这样使用:

A.ShowFrame<MyModalNoData>(); // legal
A.ShowFrame<MyModal>(new MyModalData(), …); // legal
A.ShowFrame<MyModalNoData>(new MyModalData(), …); // illegal
A.ShowFrame<MyModal>(); // illegal

但是,此解决方案可能违反您可能需要的继承自由。我还会考虑以下类型的验证:

  • 运行时:为类型参数添加类型检查,例如一些东西(typeof(IFrame<TK>)).IsAssignableFrom(typeof(T))
  • 编译时:添加一个基于 Roslyn 的自定义代码检查,该检查将捕获对ShowFrame

推荐阅读