循环依赖于接口

时间:2013-02-07 19:18:41

标签: c# .net interface

我正在重新分解和构建Win8 App解决方案。我一直在将我的关键组件分离到他们自己的项目中。我有:

  • 使用MVVMLight(以及SimpleIOC)的主要Win8项目
  • 包含所有可序列化模型类的模型项目
  • 包含各种导航和序列化类的服务项目
  • 我所有界面的合同项目
  • 包含主应用程序使用的视图模型的View Models项目。

到目前为止,我已经有了工作但有一个案例我无法找到最好的结构。在我的ViewModels项目中,我有一个数据映射器类。基本上它需要一个模型并吐出一个视图模型。我一直在尝试将其移动到服务层并为其创建一个接口,但是为了了解ViewModel类而在接口中遇到了一个依赖项,因此目前基本上存在循环依赖。

编辑:我应该解释一下ViewModels本身需要利用这个映射器。例如,我有一个整体的PageViewModel,它包含XAML页面所需的所有内容。其中一个是VehicleViewModel列表,它是包含一些视图特定属性的车辆列表。因此,PageViewModel将调用数据服务,获取Vehicle模型,然后使用映射器将其转换为VehicleViewModel。

这是界面。

namespace MyApp.Contracts
{
    public interface IDataMapperService
    {
        VehicleViewModel VehicleToVehicleViewModel(Vehicle v);
        TripViewModel TripToTripViewModel(Trip t);
    }
}

如您所见,我想从两个方法返回一个ViewModel对象。但是ViewModel项目已经引用了这个Contracts项目,所以我现在不会构建它。

我玩弄了为视图模型创建和接口的想法,但后来我有很多工作来创建接口,我不确定这是最好的方法。我忽略了一些明显的东西吗?

编辑:这是当前界面的实际实现:

 public VehicleViewModel VehicleToVehicleViewModel(Vehicle v)
    {
        var newVehicle = new VehicleViewModel(v.VehicleID, v.Make, v.Model, v.Petrol, v.Registration);

        foreach (Trip t in v.Trips)
        {
            newVehicle.Trips.Add(TripToTripViewModel(t));
        }

        IQueryable<Trip> trips = v.Trips.AsQueryable();

        var now = DateTime.Now.Date;

        var firstofmonth = new DateTime(now.Year, now.Month, 1);

        while (now.DayOfWeek != DayOfWeek.Monday) now = now.AddDays(-1);

        var weektrips = from t in trips
                        where t.Date >= now
                        select t;

        var monthtrips = from t in trips
                         where t.Date >= firstofmonth
                         select t;

        newVehicle.TripsThisWeek = weektrips.Count();
        newVehicle.MilesThisWeek = (int)Math.Round(weektrips.Sum(t => t.Mileage), 0);
        newVehicle.TripsThisMonth = monthtrips.Count();
        newVehicle.MilesThisMonth = (int)Math.Round(monthtrips.Sum(t => t.Mileage), 0);

        return newVehicle;
    }

    public TripViewModel TripToTripViewModel(Trip t)
    {
        var newTrip = new TripViewModel(t.TripID, t.Date, t.Mileage);
        return newTrip;
    }

2 个答案:

答案 0 :(得分:1)

您可以使用泛型来创建映射器接口。

namespace MyApp.Contracts
{
    public interface IDataMapperService<ViewModelT, ModelT>
    {
        ViewModelT ModelToViewModel(ModelT v);
    }
}

然后,您的服务可以返回IDataMapperService<VehicleViewModel, Vehicle>IDataMapperService<TripViewModel, Trip>。您可以为视图模型和模型创建轻量级接口,以便与通用约束一起使用。

namespace MyApp.Contracts
{
    public interface IModel {}
    public interface IViewModel {}

    public interface IDataMapperService<ViewModelT, ModelT>
        where ViewModelT : IViewModel
        where ModelT : IModel
    {
        ViewModelT ModelToViewModel(ModelT v);
    }
}

然后,要实现新界面,您需要创建一个映射器类。

public class DataMapperService : IDataMapperService<VehicleViewModel, Vehicle>
{
    public VehicleViewModel ModelToViewModel(Vehicle v)
    {
        //implementation goes here
    }
}

显然,您需要在引用合同,模型和视图模型项目的项目中实现此类。

答案 1 :(得分:0)

如果我正确理解了这个问题,那么您正试图从一个对象映射到一个视图模型。如果是这种情况,编写自己的映射器工具可能不会超出您的使用效率。查看Automapper它允许您通过调用Mapper.Map()方法将一个对象映射到另一个类型。

在我看来,你在思考你真正想要实现的目标。如果您需要VehicleViewModel,则将车辆映射到VehicleViewModel并调用您的映射方法。 Automapper使这一切变得非常容易。但总的来说,您只需要一个位于任何层上的中间映射器,它可以访问您的视图模型,并为不同类型的映射进行映射。