Let say we have something like:
public CustomType DoSomething1() {
CustomType ct = new CustomType();
try {
// do something
}
catch(Exception e) {
ct.Passed = false;
}
return ct;
}
public CustomType DoSomething2() {
CustomType ct = new CustomType();
try {
// do something
}
catch(Exception e) {
ct.Passed = false;
}
return ct;
}
public CustomType DoSomething3() {
CustomType ct = new CustomType();
try {
// do something
}
catch(Exception e) {
ct.Passed = false;
}
return ct;
}
These methods are executed by another program using reflection, and if CustomType property Passed == false, program stop executing another. It's due to architecture aspects.
Is it possible to create some attribute or something like that to avoid using try catches, so that if exception is thrown in method it will make Passed property as false and return to program? E.g.
[CatchException('Passed', false)]
public CustomType DoSomething1() {
CustomType ct = new CustomType();
// do something
return ct;
}
And if in process of 'do something' error would be thrown ct.Passed will be equal to 'false'
You can do the following:
public static T SafeProcessing<T>(Action<T> action, Action<T> onFail)
where T: new()
{
var t = new T();
try
{
a(t);
}
catch (Exception e)
{
//Log e
onFail(t);
}
return t;
}
And no you'd use it like this:
return SafeProcessing(c => DoSomething(c), c => c.Safe = false);
If I understand your question correct, you want to avoid repeating the try-catch-block. You can solve this by creating a function you are passing the logic you want to deal with.
public static CustomType CatchException(Action a)
{
CustomType ct = new CustomType();
try
{
a();
}
catch
{
ct.Passed = false;
}
return ct;
}
Now you can simply call the function with any logic you need like multiple times in a very comfortable way.
public CustomType DoSomething1()
{
return CatchException(() =>
{
//Do something
});
}
...
Related
I'm attempting to refactor a "trusted facade" which currently wraps over 50 service calls to the backend. All calls have different signatures, but everything else is being repeated. The issue with the existing calls was that there was no attempt made to manage the connections, resulting in ephemeral ports remaining in the "BOUND" state.
ORIGINAL CODE:
public class ReportWeb : IReportWeb
{
ReportService.ReportClient client = new ReportClient();
...
public string[] GetAccounts() => client.GetAccounts();
}
NEW CODE:
private ChannelFactory<IReportService> _factory = null;
private IReportService _proxy = null;
private void OpenProxy()
{
_factory = new ChannelFactory<IReportService>("NetTcpBinding_IReportService");
_proxy = _factory.CreateChannel();
}
private void CloseProxy()
{
((IClientChannel)_proxy).Close();
_factory.Close();
}
One of 50+ similar methods:
public string[] GetAccounts() // Different - name, params, and return type
{
string[] accounts = null; // Different
try
{
OpenProxy();
accounts = _proxy.GetAccounts(); // Different
CloseProxy();
}
catch (Exception exception)
{
bool faulted = _factory.State == CommunicationState.Faulted;
_factory.Abort();
if (faulted)
{
throw new ApplicationException(exception.Message);
}
else
{
throw;
}
}
return accounts;
}
Another similar method:
//Another method
public ContractsInfo[] GetContracts(int contractId) // Different -
// name, params, and return type
{
ContractsInfo[] contracts = null; // Different
try
{
OpenProxy();
contracts = _proxy.GetContracts(contractId); // Different
CloseProxy();
}
catch (Exception exception)
{
bool faulted = _factory.State == CommunicationState.Faulted;
_factory.Abort();
if (faulted)
{
throw new ApplicationException(exception.Message);
}
else
{
throw;
}
}
return contracts;
}
Calling code from Web Forms project:
public string[] GetAccounts()
{
ReportClient client = NewReportClient();
string[] results = null;
try
{
results = client.GetAccounts();
client.Close();
}
catch (Exception ex)
{
client.Abort();
throw ex;
}
return results;
}
There are over fifty other methods like GetData() with different signatures. They will all be identical except for the service call in each, which will vary in params and return type. I need a more abstract, or generic, way of coding this and thus adhere to the DRY principle. Would Func<T, TResult> Delegate be appropriate here? Either way, can someone suggest a best approach here with some stub code to illustrate?
I suppose that this is the case where Generic method with can be applied. It is
possible to read about Generics here
Let me show a code example:
public class Foo
{
public T GetDate<T, UArg>(UArg arg) where T : new()
{
return new T();
}
}
I have a program that calls dozens of methods with varying signatures, but the exception handling inside each one is identical. Is there some way to define a method that can accept a reference to a generic method with various signatures (which rules out a Delegate - right?) and return the object, or void that the method requires? I'm using .NET 4.72.
Here is stripped down version of what I'm currently doing and some pseudo-code of what I'd like to do:
static class StackOverflowQuestion
{
public static void Main(string[] args)
{
// What I'm currently doing:
MethodOne("x");
int ret = MethodTwo(0);
//.
//.
//.
MethodNineteen();
// what I'd like to do is replace MethodOne(), MethodTwo(), ..., Method Nineteen()
// with something like:
RunMethod<void>(MethodOneWork, new object[] {"x"});
ret = RunMethod<int>(MethodTwoWork, new object []{1});
//.
//.
//.
RunMethod<void>(MethodNineteenWork, null);
}
private static void MethodOne(string st)
{
try
{
// the try clause is the only difference between the methods
MethodOneWork(st);
}
catch (MyExceptionA)
{
HandleExceptionA();
return;
}
catch(MyExceptionB)
{
HandleExceptionB();
}
catch(Exception)
{
HandleGenericException();
}
}
private static int MethodTwo(int v)
{
try
{
return MethodTwoWork(v);
}
catch (MyExceptionA)
{
HandleExceptionA();
return -1;
}
catch (MyExceptionB)
{
HandleExceptionB();
return -2;
}
catch(Exception)
{
HandleGenericException();
return 0;
}
}
private static void MethodNineteen()
{
try
{
MethodNineteenWork();
}
catch (MyExceptionA)
{
HandleExceptionA();
return;
}
catch (MyExceptionB)
{
HandleExceptionB();
}
catch(Exception)
{
HandleGenericException();
}
}
/// <summary>
/// Run generic method with generic signature
/// </summary>
private static <T> RunMethod(Delegate MethodxWork, object[] myParams)
{
try
{
new <T>() retVal = MethodxWork(myParams);
return retVal;
}
catch (MyExceptionA)
{
HandleExceptionA();
return new <T>();
}
catch (MyExceptionB)
{
HandleExceptionB();
return new <T>();
}
catch(Exception)
{
HandleGenericException();
return new <T>();
}
}
private static void HandleExceptionB()
{
//handle it
}
private static void HandleExceptionA()
{
//handle it
}
private static void HandleGenericException()
{
//handle it
}
}
internal class MyExceptionB : Exception
{
}
internal class MyExceptionA : Exception
{
}
Sure, just create a few methods whose job it is to handle the exceptions, one for returning results and the other for void, and provide something that does your work.
T Handle<T>(Func<T> call)
{
try
{
return call();
}
catch(YourException ex)
{
return default;
}
}
void Handle(Action call)
{
try
{
call();
}
catch(YourException ex)
{
}
}
After that, you can call your other methods with varying signatures inside there.
var result = Handle(() => SomeCallWithVaryingSignature(...));
Handle(() => SomeOtherCall(...));
I like to use a method for different kind of classes/types. I could do something like this:
public void ClearTable(string type)
{
try
{
using (var connection = new SQLiteConnection(platform, dbPath))
{
switch (type)
{
case "Project":
connection.DropTable<Project>();
connection.CreateTable<Project>();
break;
case "Task":
connection.DropTable<Task>();
connection.CreateTable<Task>();
break;
default:
break;
}
}
}
catch (SQLiteException ex)
{
Log.Info("SQLiteEx", ex.Message);
}
}
Where, for example "Project" in DropTable is a name of a class. But I prefer more something more generic like (this is the part where I am not sure what to do):
public void ClearTable(Type t)
{
try
{
using (var connection = new SQLiteConnection(platform, dbPath))
{
connection.DropTable<t>();
connection.CreateTable<t>();
}
}
catch (SQLiteException ex)
{
Log.Info("SQLiteEx", ex.Message);
}
}
How can I use something like the last method to support multiple kind of classes/types?
You are looking for Generics
With generics you could write code like this:
public void ClearTable<TType>()
{
try
{
using (var connection = new SQLiteConnection(platform, dbPath))
{
connection.DropTable<TType>();
connection.CreateTable<TType>();
}
}
catch (SQLiteException ex)
{
Log.Info("SQLiteEx", ex.Message);
}
}
You then can call the method and give any type as generic parameter:
ClearTable<MyDomainModel>();
In additition you could restrict the generic parameter TType with a where clause.
public void ClearTable<TType>()
where TType : IDomainModel
{
// your code goes here
}
Now you can only give types which inherit from IDomainModel as generic parameter.
Depends on what the code that calls ClearTable looks like.
Compile time binding
If it knows the type at compile time, you can change your prototype to
public void ClearTable<T>()
...and call it with
var myClass = new MyClass();
myClass.ClearTable<Task>();
or
myClass.ClearTable<Project>();
Run-time binding
If the type is not known until run-time, and you truly have to pass it as a string like that, you could set up a delegate dictionary like this:
class MyClass
{
private readonly Dictionary<string, Action<SQLLiteConnection>> _actions = new Dictionary<string, Action<SQLLiteConnection>>();
public MyClass()
{
_actions.Add("Project", conn => conn.DropTable<Project>());
_actions.Add("Task", conn => conn.DropTable<Task>());
}
public void ClearTable(string type)
{
try
{
using (var connection = new SQLiteConnection(platform, dbPath))
{
var action = _actions[type](connection);
action(connection);
}
}
catch (KeyNotFoundException ex1)
{
Log.Info(String.Format("{0} is not a supported type.", type));
}
catch (SQLiteException ex2)
{
Log.Info("SQLiteEx", ex2.Message);
}
}
}
I have a lot of functions that look like this:
public void DoParticularThing(RecurringTaskRunResult result) {
try {
// Do a bunch of stuff
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
So I decided to extract this out in the name of DRY code:
public void RunThing(Action<RecurringTaskRunResult> action, RecurringTaskRunResult result) {
try {
action(result);
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
This way I can call DoParticularThing like this:
RunThing(DoParticularThing, result);
But some of my functions also accept another parameter:
public void DoOtherParticularThing(RecurringTaskRunResult result, List<string> strings) {
try {
// Do a bunch of stuff
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
How can I modify RunThing to optionally accept another parameter?
Perhaps this :
public void RunThing(Action action, RecurringTaskRunResult result) {
try {
action();
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
RunThing(() => DoParticularThing(result), result);
RunThing(() => DoSomethingElse(result, list), result);
You can use params accept any parameters in your function.
public void RunThing(Action<RecurringTaskRunResult> action, RecurringTaskRunResult result, params object[] list) {
try {
action(result);
foreach(var item in list)
{
// Do action with your additional parameter
}
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
It looks like in all cases you want RunThing to have access to the RecurringTaskRunResult so that you can set some fields on it, but that you don't need access to any of the other parameters. You could try something like this:
void Action1(RecurringTaskRunResult result) { }
void Action2(RecurringTaskRunResult result, object foo) { }
RecurringTaskRunResult result = ...;
object foo = ...;
RunThing(Action1, result);
RunThing(res => Action2(res, foo), result);
I wrote two functions which look similar, how can I optimize them?
Note:
1.AsyncCompletedEventArgs is the base class of DownloadStringCompletedEventArg and UploadStringCompletedEventArgs.
2.Result property is not in the AsyncCompletedEventArgs.
3.DownloadStringCompletedEventArgs has a Error property, if Error is null, then try to access Result property, the exception occurs.
void fun1(DownloadStringCompletedEventArgs e)
{
try
{
string s = e.Result;
}
catch (WebException eX)
{
HandleWebException();
}
}
void fun2(UploadStringCompletedEventArgs e)
{
try
{
string s = e.Result;
}
catch (WebException eX)
{
HandleWebException();
}
}
You code may be changed to something like below:
void fun1(DownloadStringCompletedEventArgs e) { Process(e); }
void fun2(UploadStringCompletedEventArgs e) { Process(e); }
private void Process(dynamic eventArgs)
{
try
{
string s = eventArgs.Result;
}
catch (WebException e)
{
HandleWebException(e);
}
}
UploadStringCompletedEventArgs and DownloadCompletedEventArgs both extend AsyncCompletedEventArgs but unfortunately the base class does not define the Result property.
A TryX pattern with a result accessor delegate might be appropriate here:
public bool TryGetResult(Func<string> resultAccessor, out string result)
{
try
{
result = resultAccessor();
return true;
}
catch(WebException)
{
HandleWebException();
result = null;
return false;
}
}
void fun1(DownloadStringCompletedEventArgs e)
{
string result;
if (TryGetResult(() => e.Result, out result))
{
// Success
}
}
void fun2(UploadStringCompletedEventArgs e)
{
string result;
if (TryGetResult(() => e.Result, out result))
{
// Success
}
}
I'd recommend trying to work in a check to AsyncCompletedEventArgs.Error, though, as exceptions are quite expensive.
Something like this:
void fun1(DownloadStringCompletedEventArgs e)
{
var result = Process<string>(e);
if (result != null)
{
// TODO your logic here
}
}
void fun2(UploadStringCompletedEventArgs e)
{
var result = Process<string>(e);
if (result != null)
{
// TODO your logic here
}
}
private T Process<T>(AsyncCompletedEventArgs result)
{
if (result.Error != null)
HandleWebException(result.Error);
else if (!result.Cancelled)
{
//var prop = result.GetType().GetProperty("Result");
//return (T) prop.GetValue(result, null);
return (T) ((dynamic)result).Result;
}
//else // TODO handle cancelled
return default(T);
}
Maybe you could write a function that takes a parameter of type AsyncCompletedEventArgs (from which both eventArg classes you use inherit) and then attempt to cast it to the correct type in your code. That would allow you to complete both in the same method, but looking at your code it probably wouldn't have much benefit for you. Good luck!