使用泛型方法时,如何正确地约束到相关的类类型



我有两个基类BaseObjectBaseObjectSettings。第一个定义对象行为,第二个定义类的状态(对序列化有用(。

如果我想创建一个具有特定设置的派生BaseObject类,那么我可以使用一个具有泛型类型约束的方法。

public void CreateBaseObjectInstance<T>(BaseObjectSettings baseObjectSettings) where T : BaseObject
{
var instance = pool.GetInstance<T>();
instance.Settings = baseObjectSettings;
scene.Add(instance);
}

我面临的问题是,虽然我可以将泛型类型约束为BaseClass,但不能将BaseClassSettings约束为相关的派生BaseClass。这意味着我可以做之类的事情

CreateBaseObjectInstance<Banana>(new AppleSettings());

这看起来有点可怕。

如果我目前被限制在将对象添加到场景之前以相同的方法创建和初始化对象,我的选项是什么?

一种方法是让所有设置类从泛型基类继承。然后,泛型基类可以从BaseObjectSettings继承。泛型类型参数指示此设置类用于何种类型的对象。

例如,对于您的AppleSettings

class AppleSettings: ObjectSettings<Apple> {
...
}
abstract class ObjectSettings<T>: BaseObjectSettings where T: BaseObject {}

现在,您可以将CreateBaseObjectInstance更改为接受ObjectSettings<T>的实例:

public void CreateBaseObjectInstance<T>(ObjectSettings<T> objectSettings) where T : BaseObject
{
var instance = pool.GetInstance<T>();
instance.Settings = objectSettings;
scene.Add(instance);
}

如果您将Banana传递为T,则它将期望ObjectSettings<Banana>,从而阻止您将其赋予AppleSettings,即ObjectSettings<Apple>

您需要创建一个通用接口或基类,在其中定义设置类型:

public class BaseObject<TSettings>
{
public TSettings Settings { get; set; }
}

然后,您的方法将需要两个通用参数——一个用于实际对象以创建TObject,另一个用于方法的参数以用于设置TSettings。然后,使用泛型参数TSettings作为约束类型的泛型参数,将TObject约束为已实现接口或其基类/派生的实现

public void CreateBaseObjectInstance<TObject, TSettings>(
TSettings settings
)
where TObject : BaseObject<TSettings>
{
...
}

示例(使用上述BaseObject实现(:

public class MyObjectSettings
{
...
}
public class MyObject : BaseObject<MyObjectSettigns>
{
}

方法调用:

var settings = new MyObjectSettings(){ ... };
CreateBaseObjectInstance<MyObject>( settings );  // second generic argument should be inferred

我真的不理解这里的逻辑,因为缺少了一些东西,但从提供的代码中,你可能可以写:

public void CreateBaseObjectInstance<TBase, TSettings>(TSettings baseObjectSettings)
where TBase : BaseObject 
where TSettings : BaseObjectSettings 

像这样使用:

CreateBaseObjectInstance<Banana, AppleSettings>(new AppleSettings());

可以改进为:

public void CreateBaseObjectInstance<TBase, TSettings>(TSettings baseObjectSettings)
where TBase : BaseObject 
where TSettings : BaseObjectSettings, new()
{
if ( baseObjectSettings == null ) baseObjectSettings = new TSettings();
...
}
CreateBaseObjectInstance<Banana, AppleSettings>();

但是,如果实体和设置之间存在强耦合,您应该重新设计,使用类似于@Sweeper和@Moho的答案的东西来定义与关联的依赖关系:

C#中的关联、组合和聚合

理解聚合、关联、组合

.NET 中的泛型

通用类和方法

最新更新