Reputation: 879
On the return of an object I want to ensure an action is performed just before if is returned. Is there a way to override the default return of an object to perform that?
for example
//In the constructor I set a query start time
var items = new ListReturnDTO<Product>();
....
//I want to set a query end time, but without the need to set the variable in code as it could be forgotten.
return items;
EDIT:
//I set the QueryStartTime in the constructor
var items = new ListReturnDTO<Product>();
items.TotalItem = 11;
........
items.data.Add(new Product { SKU = "000006", Description = "this is the test product 7, a rare breed of product", Price = 65.00, QuantityLeft = 3, Title = "Test Product 7", IsPreview = false });
items.data.Add(new Product { SKU = "000007", Description = "this is the test product 8, a rare breed of product", Price = 7.00, QuantityLeft = 30, Title = "Test Product 8", IsPreview = false });
//force a delay to replicate talking to external source
Thread.Sleep(2000);
//Currently i set QueryEndTime Here
items.QueryEndTime = DateTime.UtcNow.TimeOfDay;
//But i want it to be done automatically on the return (like how I can set QueryStartTime in the constructor, is there an equivalent/an override for the return)
return Task.FromResult(items);
Upvotes: 0
Views: 207
Reputation: 151674
So you have multiple methods or classes who perform some queries and populate your data. You want to log the query start and end times in your return object, which will always be of type ListReturnDTO<T>
, where T
is the type of entity being queried.
Your question lacks a little context, but assuming you utilize something like a repository pattern, you could make your base repository look like this, with a publicly callable method which in turn calls an abstract method that must be implemented by a derived class, offloading the actual work to a more specialized type:
public abstract class BaseRepository<TEntity>
{
public async Task<ListReturnDTO<TEntity>> QueryDataAsync()
{
var items = new ListReturnDTO<TEntity>();
items.QueryStartTime = DateTime.UtcNow;
await QueryAndPopulateDataAsync(items);
items.QueryEndTime = DateTime.UtcNow;
return items;
}
protected abstract Task QueryAndPopulateDataAsync(ListReturnDTO<TEntity> container);
}
Where you have one method, which is always called, QueryDataAsync()
, which assigns the properties you always want assigned.
Now to implement an actual repository, you inherit the base one and do the actual querying in QueryAndPopulateDataAsync()
:
public class ProductRepository : BaseRepository<Product>
{
protected override async Task QueryAndPopulateDataAsync(ListReturnDTO<TEntity> container)
{
container.TotalItem = 11;
........
container.data.Add(new Product { SKU = "000006", Description = "this is the test product 7, a rare breed of product", Price = 65.00, QuantityLeft = 3, Title = "Test Product 7", IsPreview = false });
container.data.Add(new Product { SKU = "000007", Description = "this is the test product 8, a rare breed of product", Price = 7.00, QuantityLeft = 30, Title = "Test Product 8", IsPreview = false });
//force a delay to replicate talking to external source
Thread.Sleep(2000);
}
}
And call it like this:
var repo = new ProductRepository();
var data = await repo.QueryDataAsync();
And data
will have its QueryStartTime
, QueryEndTime
and data
properties assigned.
Upvotes: 0
Reputation: 1469
As per my understanding of question
At the end of method call some code automatically. Or more specifically if return type of the method is not void, perform some action. So in given example it should update QueryEndTime.
This concept is seems like aspect oriented programming. One of the library, you might want to try, could be Postsharp. There are few others as well.
Postsharp has method decorator, which can Inject Behaviors Before and After Method Execution. Sample code from previous link
[PSerializable]
public class LoggingAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine("The {0} method has been entered.", args.Method.Name);
}
public override void OnSuccess(MethodExecutionArgs args)
{
Console.WriteLine("The {0} method executed successfully.", args.Method.Name);
}
public override void OnExit(MethodExecutionArgs args)
{
Console.WriteLine("The {0} method has exited.", args.Method.Name);
}
public override void OnException(MethodExecutionArgs args)
{
Console.WriteLine("An exception was thrown in {0}.", args.Method.Name);
}
}
static class Program
{
[LoggingAspect]
static void Main()
{
Console.WriteLine("Hello, world.");
}
}
Now coming to your example code, if it is one time look at this answer.
Upvotes: 3