Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用泛型创建流畅的界面_C#_Generics_Expression_Fluent Interface - Fatal编程技术网

C# 如何使用泛型创建流畅的界面

C# 如何使用泛型创建流畅的界面,c#,generics,expression,fluent-interface,C#,Generics,Expression,Fluent Interface,我想创建一个流畅的界面,可以这样使用: void Main() { ModelStateMappings.MapDomainModel<Book>().MapViewModel<BookViewModel>() .Properties(book => book.Author, vm => vm.AuthorsName) .Properties(book => book.Price, vm => vm.Book

我想创建一个流畅的界面,可以这样使用:

void Main() {
    ModelStateMappings.MapDomainModel<Book>().MapViewModel<BookViewModel>()
        .Properties(book => book.Author, vm => vm.AuthorsName)
        .Properties(book => book.Price, vm => vm.BookPrice);

    ModelStateMappings.MapDomainModel<Store>().MapViewModel<StoreViewModel>()
        .Properties(store => store.Owner, vm => vm.OwnersName)
        .Properties(store => store.Location, vm => vm.Location);
}
void Main(){
ModelStateMappings.MapDomainModel().MapViewModel()
.Properties(book=>book.Author,vm=>vm.AuthorsName)
.Properties(book=>book.Price,vm=>vm.BookPrice);
ModelStateMappings.MapDomainModel().MapViewModel()
.Properties(store=>store.Owner,vm=>vm.OwnersName)
.Properties(store=>store.Location,vm=>vm.Location);
}
我想最终得到一个类似这样的收藏:

static class ModelStateaMappings {
    private static IList<ModelMappings> mappings;
    // other methods in here to get it working
}

class ModelMappings {
    public Type DomainModelType {get;set;}
    public Type ViewModelType {get;set;}
    public IList<PropertyMapping> PropertyMappings {get;set;}
}

class PropertyMapping {
    public Expression<Func<object, object>> DomainProperty {get;set;}
    public Expression<Func<object, object>> ViewModelProperty {get;set;}
}
public class NamesBuilder
{
    private List<string> _names = new List<string>();
    public NamesBuilder AddName(string name)
    {
        _names.Add(name);
        return this;
    }
}
静态类modelstatemappings{
私有静态IList映射;
//这里还有其他方法可以让它工作
}
类模型映射{
公共类型DomainModelType{get;set;}
公共类型ViewModelType{get;set;}
公共IList属性映射{get;set;}
}
类属性映射{
公共表达式域属性{get;set;}
公共表达式ViewModelProperty{get;set;}
}

我无法完成上面的工作,但工作方式类似,但我并不特别喜欢如何设置流畅的界面。我宁愿让它像上面那样读。

您可以通过以下代码实现它

static class ModelStateMappings
{
    public static DomainModelMapping<TDomainModel> MapDomainModel<TDomainModel>()
    {
        // edit the constructor to pass more information here if needed.
        return new DomainModelMapping<TDomainModel>();
    }
}

public class DomainModelMapping<TDomainModel>
{
    public ViewModelMapping<TDomainModel, TViewModel> MapViewModel<TViewModel>()
    {
        // edit the constructor to pass more information here if needed.
        return new ViewModelMapping<TDomainModel, TViewModel>();
    }
}

public class ViewModelMapping<TDomainModel, TViewModel>
{
    public ViewModelMapping<TDomainModel, TViewModel>
        Properties<TDomainPropertyType, TViewModelPropertyType>(
            Expression<Func<TDomainModel, TDomainPropertyType>> domainExpr,
            Expression<Func<TViewModel, TViewModelPropertyType>> viewModelExpr)
    {
        // map here
        return this;
    }
}
静态类ModelStateMappings
{
公共静态DomainModelMapping MapDomainModel()
{
//如果需要,请编辑构造函数以在此处传递更多信息。
返回新的DomainModelMapping();
}
}
公共类DomainModelMapping
{
公共ViewModelMapping MapViewModel()
{
//如果需要,请编辑构造函数以在此处传递更多信息。
返回新的ViewModelMapping();
}
}
公共类ViewModelMapping
{
公共视图模型映射
性质(
表达式域表达式,
表达式(viewModelExpr)
{
//地图在这里
归还这个;
}
}
您不必指定所有以前设置的泛型类型,因为它们已作为返回类型的泛型参数被记住。可以跳过
属性
方法调用的泛型参数,因为编译器将推断这些参数。而且,与在任何地方使用
object
s相比,您都能获得更好的键入效果

当然,这是最简单的版本。您可以在这些类型之间传递更多信息,因为您可以指定如何创建下一个必需的类型


它还使得在不调用
MapDomainModel
的情况下调用
MapViewModel
首先是不可能的(只要将构造函数
设置为内部
并在单独的dll中关闭所有内容),这应该是一件好事。

有两种常见的方法来创建流畅的界面

一种方法是添加到正在构建的类的当前实例中,并从每个方法返回
this

大概是这样的:

static class ModelStateaMappings {
    private static IList<ModelMappings> mappings;
    // other methods in here to get it working
}

class ModelMappings {
    public Type DomainModelType {get;set;}
    public Type ViewModelType {get;set;}
    public IList<PropertyMapping> PropertyMappings {get;set;}
}

class PropertyMapping {
    public Expression<Func<object, object>> DomainProperty {get;set;}
    public Expression<Func<object, object>> ViewModelProperty {get;set;}
}
public class NamesBuilder
{
    private List<string> _names = new List<string>();
    public NamesBuilder AddName(string name)
    {
        _names.Add(name);
        return this;
    }
}
如果我看到这段代码,我希望
namebuilder1
namebuilder2
都只有一个名称,而
namebuilder
不会有任何名称。但是,实现在所有三个变量中都有这两个名称,因为它们是同一个实例

实现fluent接口的更好方法是在构建器类上创建一个链,该类将被延迟评估,以便在构建完成后创建最终的类。然后,如果你在建筑过程的中间分支,你可能会犯错误。 下面是我希望编写的代码类型:

var bookMap =
    ModelStateMappings
        .Build<Book, BookViewModel>()
        .AddProperty(book => book.Author, vm => vm.AuthorsName)
        .AddProperty(book => book.Price, vm => vm.BookPrice)
        .Create();

var bookStore =
    ModelStateMappings
        .Build<Store, StoreViewModel>()
        .AddProperty(store => store.Owner, vm => vm.OwnersName)
        .AddProperty(store => store.Location, vm => vm.Location)
        .Create();
var bookMap=
模型状态映射
.Build()
.AddProperty(book=>book.Author,vm=>vm.AuthorsName)
.AddProperty(book=>book.Price,vm=>vm.BookPrice)
.Create();
var书店=
模型状态映射
.Build()
.AddProperty(store=>store.Owner,vm=>vm.OwnersName)
.AddProperty(store=>store.Location,vm=>vm.Location)
.Create();
实现此功能的代码比“名称”示例稍微复杂一些

公共静态类ModelStateMappings
{
公共静态生成器Build()
{
返回新的生成器();
}
公共类生成器
{
公共生成器(){}
公共建筑商地址属性(
表达式域映射,
表达式(视图模型映射)
{
返回新的BuilderProperty(this、domainMap、viewModelMap);
}
公共虚拟地图创建()
{
返回新映射();
}
}
公共类生成器属性:生成器
{
私人建筑商——以前的建筑商;
私有表达式_domainMap;
私有表达式_viewModelMap;
公共建筑财产(
建筑商之前的建筑商,
表达式域映射,
表达式(视图模型映射)
{
_previousBuilder=previousBuilder;
_domainMap=domainMap;
_viewModelMap=viewModelMap;
}
公共覆盖映射创建()
{
var map=_previousBuilder.Create();
/*将当前映射添加到映射类的代码*/
返回图;
}
}
}
这种类型的生成器的另一个优点是还可以维护强类型属性字段


当然,您需要为
Create
方法中的映射输入正确的代码。

您现在拥有的界面是什么样子的?是什么具体的问题阻止了您使它看起来像您想要的那样?我不知道如何获得泛型推理,一直到.Properties()方法,同时传递这两种类型。我希望这样做的方式是一次传递每个泛型,然后在Property()方法中将它们组合在一起。听起来您需要一个类型数组。你看过吗?我看过automapper,那不是我需要的。我并不是真的用它来映射模型之间的属性。。我想用它来获取域模型中哪些属性与vie中的属性相关的表达式