Generic Function wrapper - c#

I have many functions with different content but the parameters and try catch inside is almost similar. Is there anyway to wrap the function up so that can reduce redundant codes.
ResponseStatus GetPotatoList(GetPotatosRequest requestParam, out GetPotatosResponse response, out ResponseErrorType errorType)
{
ResponseStatus status = ResponseStatus.Fail;
response = new GetPotatosResponse();
//To Do
try
{
//To Do
status = ResponseStatus.Success;
}
catch(CustomException ex)
{
errorType = ResponseErrorType.CustomError;
}
catch(TimeoutException ex)
{
errorType = ResponseErrorType.Timeout;
}
catch(Exception ex)
{
errorType = ResponseErrorType.GeneralFailure;
}
return status;
}

You can pass an Action to your method.
ResponseStatus GetPotatoList(Action action1, Action action2, GetPotatosRequest requestParam, out GetPotatosResponse response, out ResponseErrorType errorType)
{
ResponseStatus status = ResponseStatus.Fail;
response = new GetPotatosResponse();
action1();
try
{
action2();
status = ResponseStatus.Success;
}
catch(CustomException ex)
{
errorType = ResponseErrorType.CustomError;
}
catch(TimeoutException ex)
{
errorType = ResponseErrorType.Timeout;
}
catch(Exception ex)
{
errorType = ResponseErrorType.GeneralFailure;
}
return status;
}
Then use it:
var response = GetPotatoList(
() => doSomething(),
() => doSomethingElse(),
requestParam,
out response,
out errorType);

I needed to provide functionality before and after invoking an original method whose signature didn't vary much.
I used Func<..>...
public static Func<string, string> Hello = name => "hello " + name;
public static string Hello2(string name) => wrap(Hello)(name);
// This does NOT retain the name of the arg for hints in the IDE
public static Func<string, string> Hello3 = name => wrap(Hello)(name);
private static Func<string, T> wrap<T>(Func<string, T> orig)
{
return name => orig(name.ToUpper());
}

Instead using Action you should maybe use a function that will take the request as the parameter and return your response object, then you can take benefit of generics to make the call and then handle specific cases. Also returning tuple or some generic type for the Result might be a good idea instead of using out parameters.
public static Tuple<TResponse, ResponseStatus, ResponseErrorType> GetResponse<TRequest, TResponse>(Func<TRequest, TResponse> action, TRequest request)
{
var status = ResponseStatus.Fail;
var errorType = ResponseErrorType.None;
var response = default(TResponse);
try
{
response = action(request);
status = ResponseStatus.Success;
}
catch (CustomException ex)
{
errorType = ResponseErrorType.CustomError;
}
catch (TimeoutException ex)
{
errorType = ResponseErrorType.Timeout;
}
catch (Exception ex)
{
errorType = ResponseErrorType.GeneralFailure;
}
return new Tuple<TResponse, ResponseStatus, ResponseErrorType>(response, status, errorType);
}

Related

How to unify and manage overloaded functions?

This code works by taking a function as a parameter and using try-catch to log the result of the function.
When I change the functionDecorator here, I want the changes to be applied automatically to functionDecorator<T> or functionDecorator<T1, T2> without copying the entire code as it is now
These functions that do almost the same thing Is there a way to manage each other's behavior in one place, including even try-catch statements?
public void funtionDecorator(Func<bool> Func, string successText = "success", string failText = "fail", string errorText = "error")
{
try
{
if (Func())
{
txtStatusBar.Text = successText;
}
else
{
txtStatusBar.Text = failText;
}
}
catch(Exception ex)
{
txtStatusBar.Text = errorText + Func.Method.Name + ex.ToString();
}
}
// ex : funtionDecorator<DataTable>(useDataFuntion, dt);
public void funtionDecorator<T>(Func<T, bool> Func, T type, string successText = "success", string failText = "fail", string errorText = "error")
{
try
{
if (Func(type))
{
txtStatusBar.Text = successText;
}
else
{
txtStatusBar.Text = failText;
}
}
catch (Exception ex)
{
txtStatusBar.Text = errorText + Func.Method.Name + ex.ToString();
}
}
// ex : funtionDecorator<DataTable, Double>(useDataFuntion, dt, value);
public void funtionDecorator<T1, T2>(Func<T1, T2, bool> Func, T1 type1, T2 type2, string successText = "success", string failText = "fail", string errorText = "error")
{
try
{
if (Func(type1, type2))
{
txtStatusBar.Text = successText;
}
else
{
txtStatusBar.Text = failText;
}
}
catch (Exception ex)
{
txtStatusBar.Text = errorText + Func.Method.Name + ex.ToString();
}
}
I tried to handle it dynamically using dynamic, but the function type was not converted to dynamic, so I couldn't find a way.

How do i return error message in different return type function?

This function connects to postgres database and returns Dataset.
Two things i want to understant
If i get an error how can i return it ?
Is this the best way to return Dataset ?
string strODBCDriverName = "DSN=Postgres_32";
public DataSet SelectDataSet(string sql, bool isProcedure, Dictionary<string, object> parameters = null) {
using (OdbcConnection odbcConnection = new OdbcConnection(strODBCDriverName))
{
odbcConnection.Open();
using (OdbcCommand odbcCommand = new OdbcCommand(sql, odbcConnection))
{
if (isProcedure) odbcCommand.CommandType = CommandType.StoredProcedure;
else odbcCommand.CommandType = CommandType.Text;
if (parameters != null)
foreach (KeyValuePair<string, object> parameter in parameters)
odbcCommand.Parameters.AddWithValue(parameter.Key, parameter.Value);
using (OdbcDataAdapter adapter = new OdbcDataAdapter(odbcCommand))
{
using (DataSet ds = new DataSet())
{
try
{
adapter.Fill(ds); return ds;
}
catch (Exception ex)
{
throw (ex);
}
finally
{
}
}
}
}
}
}
I like having generic Result class that can be reused:
internal class Result
{
internal bool IsFailure => !IsSuccess;
internal bool IsSuccess { get; }
internal string Error { get; }
protected Result(bool isSuccess, string error) {
IsSuccess = isSuccess;
Error = error;
}
private Result(bool isSuccess) : this(isSuccess, null) { }
internal static Result Fail(string error) => new Result(false, error);
internal static Result<T> Fail<T>(string error) =>
new Result<T>(default(T), false, error);
internal static Result Ok() => new Result(true);
internal static Result<T> Ok<T>(T value) => new Result<T>(value, true);
}
internal sealed class Result<T> : Result
{
internal T Value { get; }
internal Result(T value, bool isSuccess) : this(value, isSuccess, null) { }
internal Result(T value, bool isSuccess, string error) : base(isSuccess, error) {
Value = value;
}
This can be used not only DataSet, but any type.
In your case return would be Result<DataSet> and returns can become:
returns ds --> new Result.Ok(d)
throw ex --> new Result.Fail<DataSet>(ex.Message)
I think it would be great if you return null; If you need return some customized message as well means you can use out parameters for this. So that the return value will be null if any Exception occurs in this case out parameter will holds the exception details. if Dataset is populated well means outParameter will have a values "Success" or something like that. So the method signature will be changed as like the following
public static DataSet SelectDataSet(string sql, bool isProcedure, out string message, Dictionary<string, object> parameters = null)
{
// Rest of codes here
try
{
message = "Success";
adapter.Fill(ds);
return ds;
}
catch (Exception ex)
{
message = ex.Message;
return null;
}
}
And you can call this method like this:
string message = String.Empty;
DataSet resultDataset = SelectDataSet("query here", false, out message);
if (resultDataset != null)
{
Console.WriteLine(message);
// proceed with resultDataset
}
else
{
Console.WriteLine(message);
}
Here resultDataset will be null in case of any exception otherwise you can proceed with its value.
Create a class:
class DataSetWithError: DataSet
{
public Exception msg { get; set; }
}
Save error during query:
using (OdbcDataAdapter adapter = new OdbcDataAdapter(odbcCommand))
{
DataSetWithError ds = new DataSetWithError();
try
{
adapter.Fill(ds);
}
catch (Exception ex)
{
ds.msg = ex;
}
finally
{
adapter.Close();
}
return ds;
}
And result:
DataSetWithError dataSetWithError = SelectDataSet();
if (dataSetWithError.msg == null)
{
// Show data
}
else
{
MessageBox.Show(dataSetWithError.msg.ToString());
}

Can we make this method generic?

I saw this method in a sample from Xamarin, using JSON accessing a REST Server:
List<Country> countries = new List<Country>();
public Task<List<Country>> GetCountries()
{
return Task.Factory.StartNew (() => {
try {
if(countries.Count > 0)
return countries;
var request = CreateRequest ("Countries");
string response = ReadResponseText (request);
countries = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Country>> (response);
return countries;
} catch (Exception ex) {
Console.WriteLine (ex);
return new List<Country> ();
}
});
}
where "CreateRequest" and "ReadResponseText" are methods that interact with a REST Server, basically receiving a list of countries to deserialize and return in the list.
So now, I'm trying to make this method generic in order to receive the type and return a generic list of objects of the specified type, something like this:
public static Task<List<Object>> getListOfAnyObject(string requested_object, Type type)
{
return Task.Factory.StartNew (() => {
try {
var request = CreateRequest (requested_object);
string response = ReadResponseText (request);
List<Object> objects = // create a generic list based on the specified type
objects = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Object>> (response); // not sure how to handle this line
return objects;
} catch (Exception ex) {
Console.WriteLine (ex);
return ex.Message;
}
});
}
So my question is, how can I create the method above in order to use it more and less like this (casting the list to my desired type)?
List<Country> countries = (List<Country>)(List<?>) getListOfAnyObject("countries",Country.type);
Many thanks in advance!
Try something like this..
public static Task<List<T>> getListOfAnyObject<T>(string requested_object)
{
return Task.Factory.StartNew (() => {
try {
var request = CreateRequest (requested_object);
string response = ReadResponseText (request);
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>> (response); // not sure how to handle this line
} catch (Exception ex) {
Console.WriteLine (ex);
return ex.Message;
}
});
}
Called like so..
List<Country> countries = getListOfAnyObject<Country>("countries");

Passing parameters into an Action?

I am trying to fully understand how I can simplify the following:
public ActionResult Create(string ds) {
InitializeServices(ds, "0000");
vm.Account = new Account {
PartitionKey = "0000",
RowKey = "0000",
Created = DateTime.Now,
CreatedBy = User.Identity.Name
};
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e) {
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
return View("CreateEdit", vm);
}
I had a few great answers and the following was suggested:
private void HandleException(Action action) {
try {
action();
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
}
RunAndHandleExceptions(new Action(() =>
{
//Do some computing }
));
This looks like a really great solution but I still don't understand how I can pass in my
parameters into the action. What I need to do is to pass in the following:
string ds
System.Web.Mvc.ModelState ModelState (passed as a reference)
Just
HandleException(() => someFunction(ds, ModeState));
should do it
To get the return value, you need a Func<>, not Action<>:
private TR HandleException<TR>(Func<TR> action)
{
try
{
return action();
}
catch (ServiceException ex)
{
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
return default(TR); // null for reference types
}
You then would use it, e.g. without an existing function:
bool result = HandleException(() =>
{
if (string.IsNullOrEmpty(ds))
return false;
// do interesting stuff that throws many kinds of exceptions :)
// Note: freely use ds and ModelState from surrounding scope,
// no need to 'pass them'
return true;
});
Have you looked at RedirectToAction?
return this.RedirectToAction(c => c.SomeAction(MyParam));
You can define an action with up to 16 parameters (no discussion, if that number is useful, please). So, sour call could look like:
private void HandleException(Action<string, System.Web.Mvc.ModelState ModelState > action) {
Edit
Here is an example with an action having parameter:
private void RunHandleException(Action<int> action)
{
action(someIntValue);
}
...
RunAndHandleExceptions((someInt) =>
{
//Do some computing
});
And here is an example with a function having a return value:
private void RunHandleException(Func<bool, int> action)
{
bool returnValue = action(someIntValue);
}
...
RunAndHandleExceptions((someInt) =>
{
//Do some computing
return true;
});

Passing parameters to an anonymous method using an action in C#

We are still having problems passing a parameter to an action. Here's what we have so far:
public ActionResult Create(string ds) {
HandleException(new Action<string, ref System.Web.Mvc.ModelState>(ds,ModelState) => {
InitializeServices(ds, "0000");
vm.Account = new Account {
PartitionKey = "0000",
RowKey = "0000",
Created = DateTime.Now,
CreatedBy = User.Identity.Name
};
});
return View("CreateEdit", vm);
}
private void HandleException(Action action) {
try {
action();
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
}
This gives 12 syntax errors and most are pointing to the line:
HandleException(new Action<string,
We have also have syntax errors saying that "ref" is not the correct syntax
Generic types expect types as their parameters... So Action requires actual types for each argument. "ref Type" is not a type. Ref is just a keyword.
As Jakub suggests, you should remove "ref" altogether and mutate your ModelState
The argument of HandleException is of type Action, but you call it with an object of type Action<string, ref System.Web.Mvc.ModelState>, which is a specialization of Action<T1, T2>. These two types must be the same, just choose one of them.
public ActionResult Create(string ds) {
HandleException(() => {
InitializeServices(ds, "0000");
vm.Account = new Account {
PartitionKey = "0000",
RowKey = "0000",
Created = DateTime.Now,
CreatedBy = User.Identity.Name
};
});
return View("CreateEdit", vm);
}
private void HandleException(Action action) {
try {
action();
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
}

Categories

Resources