Creating a Generic Save() Method for Models

白昼怎懂夜的黑 提交于 2019-12-09 19:02:53

问题


I have a fairly simple system, and for the purposes of this question there are essentially three parts: Models, Repositories, Application Code.

At the core are the models. Let's use a simple contrived example:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

In that same project is a generic repository interface. At its simplest:

public interface IRepository<T>
{
    T Save(T model);
}

Implementations of that interface are in a separate project and injected with StructureMap. For simplicity:

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.
    }
}

So, in application code, if I wanted to save a model I would do this:

var rep = IoCFactory.Current.Container.GetInstance<IRepository<Person>>();
myPerson = rep.Save(myPerson);

Simple enough, but it feels like it could be automated a lot. That pattern holds throughout the application code, so what I'm looking to do is create a single generic Save() on all models which would just be a shorthand call to the above application code. That way one would need only call:

myPerson.Save();

But I can't seem to figure out a way to do it. Maybe it's deceptively simple and I'm just not looking at it from the correct angle. At first I tried creating an empty ISaveableModel<T> interface and intended to have each "save-able" model implement it, then for the single generic Save() method I would have an extension on the interface:

public static void Save<T>(this ISaveableModel<T> model)
{
    var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
    model = rep.Save(model);
}

But it tells me that rep.Save(model) has invalid arguments. It seems that it's not wiring up the type inference as I'd hoped it would. I tried a similar approach with a BaseModel<T> class from which models would inherit:

public class BaseModel<T>
{
    public void Save()
    {
        this = IoCFactory.Current.Container.GetInstance<IRepository<T>>().Save(this);
    }
}

But the compiler error is the same. Is there a way to achieve what I'm trying to achieve? I'm very flexible on the design, so if I'm going about something all wrong on an architectural level then I have room to step back and change the big picture.


回答1:


Would a generic extension method solve it?

public static T Save<T>(this T current)
{
    var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
    rep.Save(current);
}

You can then constrain it to your ISaveableModel<T> interface. Return type above not implemented, but you can put it to a boolean or status flag, whatever.




回答2:


In both approaches, the parameter to the Save() function is not of type T. In the first one, it is ISaveableModel<T>, and in the second, it is BaseModel<T>. Since the repository is a generic based on T, Save method will expect a variable of type T. You can add a simple cast to T before you call Save to fix it.

Alternatively, your IRepostory<T> can be changed to

public interface IRepository<T>
{
    T Save(ISaveableModel<T> model);
}

which makes more sense.



来源:https://stackoverflow.com/questions/6395993/creating-a-generic-save-method-for-models

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!