我有一个相当简单的系统,为了这个问题的目的,基本上有三个部分:模型,存储库,应用程序代码。
核心是模型。让我们使用一个简单的人为例子:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
在同一个项目中是一个通用的存储库接口。最简单的是:
public interface IRepository<T>
{
T Save(T model);
}
该接口的实现位于单独的项目中,并使用StructureMap注入。为简单起见:
public class PersonRepository : IRepository<Person>
{
public Person Save(Person model)
{
throw new NotImplementedException("I got to the save method!");
// In the repository methods I would interact with the database, or
// potentially with some other service for data persistence. For
// now I'm just using LINQ to SQL to a single database, but in the
// future there will be more databases, external services, etc. all
// abstracted behind here.
}
}
因此,在应用程序代码中,如果我想保存模型,我会这样做:
var rep = IoCFactory.Current.Container.GetInstance<IRepository<Person>>();
myPerson = rep.Save(myPerson);
很简单,但感觉它可以自动化很多。该模式贯穿整个应用程序代码,因此我要做的是在所有模型上创建一个通用Save()
,这只是对上述应用程序代码的简写调用。这样一个人只需要打电话:
myPerson.Save();
但我似乎无法找到办法。也许它看似简单,我只是没有从正确的角度看它。起初我尝试创建一个空ISaveableModel<T>
接口,并打算让每个“可保存”模型实现它,然后对于单个通用Save()
方法,我将在接口上有一个扩展:
public static void Save<T>(this ISaveableModel<T> model)
{
var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
model = rep.Save(model);
}
但是它告诉我rep.Save(model)
有无效的参数。似乎它没有像我希望的那样连接类型推断。我尝试了一个类似的方法,使用BaseModel<T>
类来继承模型:
public class BaseModel<T>
{
public void Save()
{
this = IoCFactory.Current.Container.GetInstance<IRepository<T>>().Save(this);
}
}
但编译错误是一样的。有没有办法实现我想要实现的目标?我对设计非常灵活,所以如果我在建筑层面上发生了一些错误,那么我就有空间退一步改变大局。
答案 0 :(得分:3)
通用扩展方法会解决吗?
public static T Save<T>(this T current)
{
var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
rep.Save(current);
}
然后,您可以将其约束到ISaveableModel<T>
界面。上面的返回类型没有实现,但你可以把它放到一个布尔或状态标志,无论如何。
答案 1 :(得分:1)
在这两种方法中,Save()
函数的参数不是T
类型。在第一个中,它是ISaveableModel<T>
,在第二个中,它是BaseModel<T>
。由于存储库是基于T
的通用存储库,因此Save
方法将期望类型为T
的变量。在致电T
进行修复之前,您可以向Save
添加一个简单的演员。
或者,您的IRepostory<T>
可以更改为
public interface IRepository<T>
{
T Save(ISaveableModel<T> model);
}
这更有意义。