Reputation: 6790
I have a method SaveChanges<T>(T object)
that is frequently called throughout my code, except depending on the action calling the method, there would be a different method called from within SaveChanges. Something like this...
protected void SaveChanges<T>(T mlaObject, SomeFunction(arg))
where T : WebObject
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
SomeFunction(arg);
}
}
Usage Examples:
SaveChanges<MlaArticle>(article, article.Authors.Remove(person)) //person is an object of type MlaPerson
//OR
SaveChanges<MlaArticle>(article, article.RelatedTags.Remove(tag)) //tag is an object of type Tag
//OR
SaveChanges<MlaArticle>(article, article.RelatedWebObjects.Remove(location)) //location is an object of type MlaLocation
I've read up on delegate methods but I'm a little confused as to how to implement this with my requirements or if my requirements warrant use for delegates at all.
EDIT: Also, would it be possible to pass multiple Actions?
Upvotes: 8
Views: 460
Reputation: 509
protected void SaveChanges<T>(T mlaObject, Action<T> functionToCall)
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
functionToCall(mlaObject);
}
}
Call like this:
SaveChanges(actualArticle, article => article.Authors.Remove(person));
I left out the WebObject bit as it was not used in the function at all.
Upvotes: 0
Reputation: 136074
Your SaveChanges
method would look something like:
protected void SaveChanges<T,TArg>(T mlaObject, TArg arg, Action<T,TArg> someFunction)
where T : WebObject
{
...
}
Called like:
SaveChanges<MlaArticle,Person>(article,person, (article,person) => article.Authors.Remove(person))
Upvotes: 4
Reputation: 64068
How about:
protected void SaveChanges<T>(T mlaObject, Action<T> rollback)
where T : WebObject
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
rollback(mlaObject);
}
}
Called like:
this.SaveChanges(myObj, x => article.Authors.Remove(x));
Now, from a second read of your question, I don't see a point in passing the mlaObject
as it is never used.
// this.SaveChanges(
// () => article.Authors.Remove(author),
// () => article.RelatedTags.Remove(tag));
protected void SaveChanges(params Action[] rollbacks)
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
foreach (var rollback in rollbacks) rollback();
}
}
// Overload to support rollback with an argument
// this.SaveChanges(
// author,
// article.Authors.Remove,
// authorCache.Remove);
protected void SaveChanges<T>(T arg, params Action<T>[] rollbacks)
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
foreach (var rollback in rollbacks) rollback(arg);
}
}
Upvotes: 10
Reputation: 28698
if my requirements warrant use for delegates at all.
If you want the SaveChanges
method to perform some function you have two options
SaveChanges
method as a delegate.When to use each of these is a design choice that is up to you and will depend on the scenario, the overall solution and your preference.
Benefits of the first
SaveChanges
method in one placeBenefits of the second
SaveChanges
method (it doesn't require an enormous case
or if else if else if
)SaveChanges
method can be above it in the call stack, it doesn't need to know what they are or how they work, they can do things it doesn't understand, and they can be reused - called elsewhere or used as delegates in other functions.I think the first point is the main one here. If you are only handling a couple of scenarios then it's okay to have a an if else if else if
, but if you get more than a handful of options and prefer a more generic SaveChanges
method then psdd that delegate.
Upvotes: 0
Reputation: 38397
UPDATE I was a little unclear from your question if the arg passed in is being used anywhere else in the method, it doesn't look like it is, so you can just take an Action
and use a lambda to specify the delegate to call with the captured argument:
protected void SaveChanges<T, TArg>(T mlaObject, TArg arg, Action undoFunction)
where T : WebObject
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
undoFunction();
}
}
To which you can pass:
SaveChanges(article, () => article.Authors.Remove(person));
Or if it's the myObj itself, in which case (as sixlettervariables already answered) you can just pass it back in a delegate as per his code.
Or, whether the arg is different from mlaObject and you want to also do other things on it in the code, in which case you could do:
protected void SaveChanges<T, TArg>(T mlaObject, TArg arg, Action undoFunction)
where T : WebObject
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
undoFunction(arg);
}
}
And then have:
SaveChanges(article, person, article.Authors.Remove);
Upvotes: 7
Reputation: 103742
protected void SaveChanges<T,U>(T mlaObject, Action<U> action, U arg)
where T : WebObject
{
try { this._db.SaveChanges(); }
catch (Exception e)
{
Console.WriteLine("Error: " + e);
action(arg);
}
}
Hope I understood the question correctly...
Upvotes: 5