从我的标题中可能有点难以理解我想要实现的目标,所以我会进一步了解细节。
我有以下界面:
public interface IModelBuilder<T>
where T : IStandardTemplateTemplate
{
M Build<M>(T pTemplate, params object[] pParams) where M : BaseModel;
}
现在我想在我的实际构建器中实现该接口。我用来映射不同对象类型的构建器。所以这看起来如下:
public class BusinessModelBuilder : IModelBuilder<IBusinessTemplate>
{
public virtual M Build<M>(IBusinessTemplate pTemplate, params object[] pParams) where M : BussinessModel
{
var businessModel = Activator.CreateInstance<M>();
// map data
return businessModel;
}
}
现在问题如下。我不能让约束工作。由于我在接口上定义了约束,因此即使我的BusinessModel继承自BaseModel,也不会让我对实际方法使用不同的约束。它一直告诉我我的约束M必须与界面的约束相匹配。我尝试了几种不同的方法,但似乎都没有。
有谁知道是否或如何实现这一目标?我只是想在接口中告诉我允许继承模型的约束。
答案 0 :(得分:4)
这是一个简短但完整的问题示例:
public class Parent { }
public class Child { }
public interface Interface
{
void Foo<T>() where T : Parent;
}
public class Implementation : Interface
{
public void Foo<T>() where T : Child
{
}
}
这不会编译,原因与你的不一样。接口方法的实现必须对泛型参数具有完全相同的约束,它不能具有更严格的约束。
您的Build
方法只能将类型约束为BaseModel
,而不是BussinessModel
。
如果您更改IModelBuilder
接口以添加其他类级别泛型参数,然后使用 作为约束,那么您可以获得所需的功能:
public interface IModelBuilder<T, Model>
where T : IStandardTemplateTemplate
where Model : BaseModel
{
M Build<M>(T pTemplate, params object[] pParams) where M : Model;
}
public class BusinessModelBuilder : IModelBuilder<IBusinessTemplate, BussinessModel>
{
public virtual M Build<M>(IBusinessTemplate pTemplate, params object[] pParams)
where M : BussinessModel
{
var businessModel = Activator.CreateInstance<M>();
// map data
return businessModel;
}
}
此解决方案部分基于Reed's answer,但更进了一步。
答案 1 :(得分:2)
你需要将两者都放在类约束中:
public interface IModelBuilder<T, M>
where T : IStandardTemplateTemplate
where M : BaseModel
{
M Build<M>(T pTemplate, params object[] pParams);
}
然后您可以使用:
public class BusinessModelBuilder : IModelBuilder<IBusinessTemplate, BusinessModel>
{
public virtual BusinessModel Build(IBusinessTemplate pTemplate, params object[] pParams)
{
//...
答案 2 :(得分:0)
您可以稍微改变一下您的界面,包括例如
public interface IModelBuilder<T,M>
where T : IStandardTemplateTemplate
where M: BaseModel
{
M Build<M>(T pTemplate, params object[] pParams);
}
并使用如下
public class BusinessModelBuilder : IModelBuilder<IBusinessTemplate,BusinessModelBuilder>
答案 3 :(得分:0)
这是因为约束实际上是不同的,所以它不满足接口。
IModelBuilder<IBusinessTemplate> sample = new BusinessModelBuilder();
sample.Build(??)
编译器期望Build
的参数为BaseModel
,但由于您可以使用BaseModel
继承的类型不是BusinessModel
,显然无效。
现在,为了解决问题的实际问题,你可以用另一个通用参数解决这个问题。
public interface IModelBuilder<TemplateType, ConstraintType>
{
public ConstraintType Build<ConstraintType>(TemplateType template, params object[] parameters);
}
或者,如果你真的想要疯狂(假设这甚至适用于你的论点),你可以切换一些东西并获得一些通用的类型推断:
public interface IStandardTemplate<TModel> { }
public interface IModelBinder<TModel>
{
TModel ApplyParameters(IStandardTemplate<TModel> template, params object[] parameters);
}
public class ModelBuilder
{
public TModel Build<TModel>(IStandardTemplate<TModel> template, params object[] parameters)
{
var model = Activator.CreateInstance<TModel>();
var modelBinder = ModelBinderFactory.CreateBinderFor(model);
return modelBinder.ApplyParameters(template, parameters);
}
}
然后您可以简单地制作各种ModelBinder类并将它们关联到您的工厂中。
示例电话:
public class BusinessTemplate : IStandardTemplate<BusinessModel> { }
var businessTemplate = new BusinessTemplate();
var model = new ModelBinder().Build(businessTemplate); // model is of type 'BusinessModel'