I have the follwoing code and I would like to write it in a way that I have minimum lines of code and the work is done the same way. How can I do that?
List<Category> categoryList = new List<Category>();
categoryList = Category.LoadForProject(project.ID).ToList();
List<string> categories = new List<string>(Categories);
IList<Category> currentCategories = Category.LoadForProject(project.ID).ToList();
if (currentCategories != null)
{
foreach (var existingCategories in currentCategories)
{
if (categories.Contains(existingCategories.Name))
categories.Remove(existingCategories.Name);
else
existingCategories.Delete(Services.UserServices.User);
}
foreach (string item in categories)
{
Category category = new Category(project, item.ToString());
category.Project = project;
category.Save();
}
}
List<string> priorities = new List<string>(Priorities);
IList<Priority> currentPriorities = Priority.LoadForProject(project.ID).ToList();
if (currentPriorities != null)
{
foreach (var existingPriorities in curre开发者_Python百科ntPriorities)
{
if (priorities.Contains(existingPriorities.Name))
priorities.Remove(existingPriorities.Name);
else
existingPriorities.Delete(Services.UserServices.User);
}
foreach (string item in priorities)
{
Priority priority = new Priority(project, item.ToString());
priority.Project = project;
priority.Save();
}
}
Something like this should do it:
public IList<T> DoYourThing<T>(IList<T> items, IList<T> currentItems, Project project) where T : CommonBaseType
{
if (currentItems != null)
{
foreach (var existingItem in currentItems)
{
if (items.Contains(existingItem.Name))
items.Remove(existingItem.Name);
else
existingItems.Delete(Services.UserServices.User);
}
foreach (string item in items)
{
T newItem = Activator.CreateInstance(typeof(T), new object[] {project, item.ToString()}) as T;
newItem.Project = project;
newItem.Save();
}
}
return currentItems;
}
Then you can call it like this:
var currentCategories = DoYourThing(Categories.ToList(), Category.LoadForProject(project.ID).ToList());
var currentProjects = DoYourThing(Priorities.ToList(), Priority.LoadForProject(project.ID).ToList());
Finally, you should note two things in particular:
First, there is a generic condition on the function where T : CommonBaseType
. I am assuming that Category and Project have a common base type or interface that includes Name. If not, you should get rid of the condition and use Dynamic to get at Name.
Second, I am using Activator.Create to create the class for you. This is the tricky part that makes it difficult to figure out, if you don't know that trick
Good luck!
Make Priority and Category implement the same Interface or derive from a class with the common properties in it (i.e. .Project, .Name and .Save). Then use that Interface or base class as the type of your function and you will be able to pass collections of both classes to it.
Okay, as far as i understood, you want to add the categories/priorities of the "new" list, that are not existant in the repository.
make that.
public void SaveNewItems<T>(IList<string> newList, IList<T> currentList, string project)
where T: new(), IStoreableItem
{
//find only new items
var toAdd = from itemName in newList
where !currentList.Contains(i => i.Name = itemName)
select new T {
Name = itemName,
Project = project
};
//find items to delete
var toDelete = from item in currentList
where !newList.Contains(item.Name)
select item;
toAdd.ToList().ForEach(item => item.Save());
toDelete.ToList().ForEach(item => item.Delete());
}
Category and Prio must derive from IStoreableItem that contains the name, project, and save/delete method.
If Priority
and Category
are either both derived from the same base class with a common set of methods / properties, or implement the same interface then yes, you can. You will just need to replace the specific references to Priority
and Category
with references to either that base class or interface (as applicable).
There's a few minor code differences (like the List<string>(Categories)
in the first code block) that you will have to think about how to handle, but most of the code will just fall into place once the ancestor / interface question is settled.
I find dynamic
very useful for sets of types that expose the same property, but don't implement the same interface.
Iterate through the list with foreach(dynamic d in myList)... d.Name...
, wrap it into a method, and pass different IList<object>
instances (categories or priorities).
Requires C# 4.0.
You need to make Priority and Category derive from the same base class... and then you could do something along the lines of:
public void ProcessLists<ItemType>(Func<int, IEnumerable<ItemType>> Loader) whereItemType : CommonBase, new() {
List<string> items = new List<string>();
IList<ItemType> currentItems = Loader(project.ID).ToList();
if (currentItems != null) {
foreach (var existingItem in currentItems) {
if (items.Contains(existingItem.Name))
items.Remove(existingItem.Name);
else
existingItem.Delete(Services.UserServices.User);
}
foreach (string item in items) {
ItemType item = new ItemType();
item.Project = project
item.Name = item.ToString();
item.Save();
}
}
}
Of course, some types (such as the project.ID) are merely guessed and should be replaced with the proper lines.
You can call the function for Priority in this way:
ProcessLists<Priority>(id => Priority.LoadForProject(project.ID));
精彩评论