5

从我的标题可能有点难以理解我想要实现的目标,所以我会更详细地介绍一下。

我有以下界面:

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 必须匹配来自界面的约束。我尝试了几种不同的方法,但似乎都没有奏效。

有谁知道这是否或如何实现?我只想在接口中告诉我的约束允许继承模型。

4

4 回答 4

5

这是您的问题的简短但完整的示例:

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 的回答,但更进一步。

于 2013-08-09T17:34:05.523 回答
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)
   {
       //...
于 2013-08-09T17:31:19.123 回答
0

这是因为约束实际上是不同的,所以它不满足接口。

IModelBuilder<IBusinessTemplate> sample = new BusinessModelBuilder();
sample.Build(??) 

编译器会期望参数Build是 a BaseModel,但是由于你可以有一个继承自BaseModelnot a的类型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'
于 2013-08-09T17:46:09.503 回答
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>
于 2013-08-09T17:34:00.690 回答