Wrap Function / Avoid repeating coid - c#

I'm new to c# and I have a (for me:) complex application with a grpc-interface.
I have about 20 (and rising) different functions where I pass different parameters and return different types:
private async Task<VersionOfInterfaceReply> Function1()
{
...
}
private async Task<ReturnInfoReply> Function2(
List<NozzleToChange> nozzlelist,
SideType side = SideType.Right,
UInt32 processingarea = 1)
{
...
}
afterwards I want call,get,evaluate these testresults and repeat some functions.
{
ResetTestResult();
result = await Function1();
if (result.success = true) { testresult.TestLog += $"message with variables of result\n"; }
TestPassed(result);
ResetTestResult();
result = await Function2(x,y,z);
if (result.success = true) { testresult.TestLog += $"{result.xy} message with variables of result\n"; }
TestPassed(result);
}
result is already a dynamic variable (if you know better ways let me know)... but my question is following:
How can I get rid of the ResetTestResult(); and Testpassed(result) with some kind of wrapping my functions?
Is this even possible with different output/parameter types and different amount of parameters
I would like to have something like:
privat async Task? / or void CallFunction(Method givenMethod, string message)
{
ResetTestResult();
result = await givenMethod();
if (result.success = true) { testresult.TestLog += $""+message +" with variables of result\n"; }
TestPassed(result);
}
and call this like this:
{
...
CallFunction(Function1(),"message1");
CallFunction(Function2(x,y,z),"message2 {variable2}");
...
}
I tried understanding delegates, func, and actions, but im not really sure if this works for me. And another problem is the async part...
If you need any further information let me know.
thanks for your help in advance
kind regards
chris

Assuming VersionOfInterfaceReply and ReturnInfoReply implement an interface, such as:
interface IReply
{
bool Success { get; }
}
You could write your method like this:
private async Task CallFunction<T>(Func<Task<T>> givenMethod, Func<T, string> message)
where T : IReply
{
ResetTestResult();
T result = await givenMethod();
if (result.Success) { testresult.TestLog += message(result); }
TestPassed(result);
}
And use as follows:
await CallFunction(Function1, x => "message1");
await CallFunction(() => Function2(x, y, z), x => $"message2 {x.Variable2}");
To call methods with arguments, you can create a closure using a lambda expression.
Working example

Related

C# - Try something twice if if-statement is true

I have a code parsing a website and adding some values to a list. Sometimes I need to parse the website two times and add the second parsevalues to the same list.
This is some of the code:
public async Task<IEnumerable<Info>>....
{
var values = new List<Info>();
var request = something;
var request_rewritten = rewritten request to run the second time;
......
if request contains something do all the under two times. Both for the request and the rewritten request and add it to result.
......
var response = await RequestBytes(request);
var results = Encoding.GetEncoding("iso-8859-1").GetString(response.Content);
_fDom = results;
try
{
do something and a lot of code
......
values.Add(result);
return result
}
}
If request contains something I need try try a second time. Both for the original request and the rewritten request and add both to the result. Can this be done?
You can follow this pattern. Add an additional parameter to your method indicating retries remaining.
void DoSomething(arg1, arg2, int retriesRemaining = 0)
{
try
{
DoWork();
}
catch
{
if (retriesRemaining) DoSomething(arg1, arg2, --retriesRemaining);
}
}
I suppose if you want to avoid writing a method (which is the best answer to your question) you can use a flag:
bool bRunAgain = true;
while (bRunAgain)
{
// Your logic, check result and see if you need to run it again
if (your condition to run again == false)
{
bRunAgain = false;
}
}
Here is a common solution. Pass an action to this method and specify retries count
public bool ExecuteWithRetry(Action doWork, int maxTries=1) {
for(var tryCount=1; tryCount<=maxTries; tryCount++){
try{
doWork();
} catch(Exception ex){
if(tryCount==MaxTriex){
Console.WriteLine("Oops, no luck with DoWork()");
return false;
}
}
return true;
}
}
so in your method
void Something(){
....
if(ExecuteWithRetry(()=>NotTrustyMethod(), 2)) {
//success
} else {
//fail
}
}
void NotTrustyMethod(){ ...}
This solution you can use for any case where you need retry option for methods with any type of arguments (or without them)

Check whether an argument of ObjectCreationExpressionSyntax is wrapped in try catch block or not

I'm trying to write a code analysis rule with roslyn.
Basically, I have to check whether an each of arguments which a Microsoft.Practices.Prism.Commands.DelegateCommand() is created is wrapped in try catch or not.
The main idea is collect all ObjectCreationExpressionSyntax objects of DelegateCommand class and check each constructor's argument if the first StatementSyntax is TryStatementSyntax or not.
Can you help me with getting all StatementSyntax from ArgumentSyntax ? Or may be you have an another approach ?
public IEnumerable<IdentifierInfo> Collect(SyntaxNode rootNode, SemanticModel semanticModel)
{
ObjectCreationExpressionSyntax[] objCreation = rootNode
.DescendantNodes()
.OfType<ObjectCreationExpressionSyntax>()
.Where(c=>(c.Type as IdentifierNameSyntax)?.Identifier.Value.ToString() == "DelegateCommand")
.ToArray();
foreach (var obj in objCreation)
{
var args = obj.ArgumentList.Arguments;
foreach (ArgumentSyntax arg in args)
{
var expession = arg.Expression;
var symbol = semanticModel.GetSymbolInfo(expession).Symbol as IMethodSymbol;
}
}
}
Bellow you can find what I actually compile for searching through:
public class Program
{
public delegate void MyDelegate();
public static void DelegateMethod() { try { } catch { } }
public static void Main(string[] args)
{
DelegateCommand del1 = new DelegateCommand(() => {try{}catch{}});
DelegateCommand del2 = new DelegateCommand(new Action(() => { }));
DelegateCommand del3 = new DelegateCommand(DelegateMethod);
var barInit = (Action)(DelegateMethod);
DelegateCommand del4 = new DelegateCommand(barInit);
ICommand test;
test = new Microsoft.Practices.Prism.Commands.DelegateCommand(() => { });
}
}
You start in a good way, but to handle it completely, its required more work.
Lets see in your example what we have
(The screenshot is from LINQ debugging feature from OzCode)
Here what I wrote is
var argsExpr = objCreation.Select(o => o.ArgumentList.Arguments.First())
As you can see in the right side of the window, we have a three types of syntax nodes in the arguments, so we don't have a general way to handle them all.
You have two ways to handle it.
Write method that get SyntaxNode and according to its type, check if the first statement is a try\catch statement
Write SyntaxWalker and visit relevant methods, and there, check if the first statement is a try\catch statement
For example to handle the first case which is ParenthesizedLambdaExpressionSyntax you need to write something like this (or by yourself or by overriding the appropriate Visit method of the SyntaxWalker)
public static bool IsTryStatement(ParenthesizedLambdaExpressionSyntax node)
{
return ((BlockSyntax) node.Body).Statements.First() is TryStatementSyntax;
}
This is just an example. In your real code you need to handle all cases.
For the IdentifierNameSyntax you need to get the method symbol first:
semanticModel.GetSymbolInfo(identifier).Symbol
Then you need to get the syntax node from DeclaringSyntaxReferences and use span, or you can use location of the symbol or any other way (ConstructFrom maybe).

How to pass code blocks (not full methods) as arguments in C#?

I'm building a messaging app in csharp (.net 4.0), my class has basic methods for sending/receiving messages:
void sendMessage( string msgBody, string properties);
object getNextMessage();
object getMessageById( string msgId);
Each of these methods depends on an underlying connection; if the connection is stale, I use try/catch and some retry logic to make additional attempts, something like this:
public object getNextMessage(){
object nextMessage = null;
int retryAttempts = 0;
int MAX_ATTEMPTS = 3;
while( retryAttempts < MAX_ATTEMPTS){
retryAttempts++;
try{
nextMessage = connection.getMessage("queueName");
}catch(Exception e){
}
}
return nextMessage;
}
Since the retry logic is generic, I want to avoid repeating the same code in each method. I want to create a common retry function and do something like this:
public object makeAttempt( CodeBlock codeBlock){
while( retryAttempts < MAX_ATTEMPTS){
retryAttempts++;
try{
return codeBlock.invoke()
}catch(Exception e){
}
}
return null;
}
..I want to use makeAttempt like this, or something similar:
public object getNextMessage(){
makeAttempt() => {
return connection.getMessage("queueName");
}
}
I reviewed this, but it relates to passing entire functions as arguments, which I'm not doing. I also reviewed .net Lambda Expressions, but I'm not seeing a connection.
I haven't done much C# so forgive the n00b question :-)
You're nearly there at the end - you just need to enclose the lambda expression in () as it's a method argument. You also need to use the return value from makeAttempt to provide a return value for your getNextMessage method. So:
public object getNextMessage(){
return makeAttempt(() => {
return connection.getMessage("queueName");
});
}
Or more simply, use an expression lambda:
public object getNextMessage(){
return makeAttempt(() => connection.getMessage("queueName"));
}
This is all assuming that CodeBlock is a delegate type, of course, e.g.
public delegate object CodeBlock();
You also need to change makeAttempt to call Invoke rather than invoke - C# is case-sensitive. I'd strongly urge you to follow .NET naming conventions, too, where methods are PascalCased instead of camelCased.
EDIT: As noted in comments, you could make this generic:
public T CallWithRetries<T>(Func<T> function)
{
for (int attempt = 1; attempt <= MaxAttempts; attempt++)
{
try
{
return function();
}
catch(Exception e)
{
// TODO: Logging
}
}
// TODO: Consider throwing AggregateException here
return default(T);
}

Using Action<T> as an argument in C# (mimicking a function pointer)

I need to write a delegate function that can 'wrap' some while/try/catch code around a basic UDP call to verify the link.
I made it work for Func for a function that has no arguments, but I can't make it work for Action, which has an argument (but no return). I can't seem to pass in the argument in a logical way without the compiler complaining.
Am I going about this all wrong? I'm new to C# and I'm essentially trying to mimick the idea of a function pointer. Should I not be overloading this function? I know you can't overload delegates (I assume that's why Func and Action exist).
This works:
protected TResult udpCommand<TResult>(Func<TResult> command)
{
TResult retValue = default(TResult);
while (!linkDownFail)
{
try
{
retValue = command();
break;
}
catch
{
LinkStateCallBack(ip, getLinkStatus());
if (linkDownFail) throw new LinkDownException();
Thread.Sleep(100);
}
}
return retValue;
}
But this does not:
protected void udpCommand<T>(Action<T> command(T value))
{
while(!linkDownFail)
{
try
{
command(value);
break;
}
catch
{
LinkStateCallBack(ip, getLinkStatus());
if (linkDownFail) throw new LinkDownException();
Thread.Sleep(100);
}
}
return;
}
Calling convention (for one that works):
udpCommand<uint>(someUdpCommand);
If you want this to be generic enough to handle any number of arguments, try using the non-genernic Action delegate:
protected void udpCommand(Action command)
{
while(!linkDownFail)
{
try
{
command();
break;
}
catch
{
LinkStateCallBack(ip, getLinkStatus());
if (linkDownFail) throw new LinkDownException();
Thread.Sleep(100);
}
}
return;
}
In C# 3.0, you can call it like this:
udpCommand(() => noParameterMethod());
udpCommand(() => singleParameterMethod(value));
udpCommand(() => manyParameterMethod(value, value2, value3, value4));
In C# 2.0 it's a little uglier:
udpCommand(delegate { noParameterMethod(); });
udpCommand(delegate { singleParameterMethod(value); });
udpCommand(delegate { manyParameterMethod(value, value2, value3, value4); });
This gives you deferred execution without locking you into a particular method signature.
EDIT
I just notice I kinda stole Marc Gravell's comment... apologies Marc. To answer how you might reduce your duplication, you can have the Action method call the Func<T> method, like this:
protected void udpCommand(Action command)
{
udpCommand(() => { command(); return 0; });
}
I believe (and I may be wrong) that returning 0 is no more costly than (implicitly) returning void, but I may be way off here. Even it it does have a cost, it would only put a tiny itty bitty snoodge extra on the stack. In most cases, the additional cost won't ever cause you any grief.
Do you mean:
protected void udpCommand<T>(Action<T> command, T value) {...}
With calling:
udpCommand(someUdpCommand, arg);
Note that this may work better on C# 3.0, which has stronger generic type inference than C# 2.0.
I think you just need to take out the (T value) after 'command'.
Are you trying to do this ...
protected void udpCommand<T>(Action<T> command, T value)
{
while(!linkDownFail)
{
try
{
command(value);
// etc.
}
}
}
Then it would work like this ...
public void ActionWithInt( int param )
{
// some command
}
Action<int> fp = ActionWithInt;
udpCommand<int>( fp, 10 ); // or whatever.

How do i exit a List<string>.ForEach loop when using an anonymous delegate?

In a normal loop you can break out of a loop using break. Can the same be done using an anonymous delegate?
Example
inputString and result are both declared outside the delegate.
blackList.ForEach(new Action<string>(
delegate(string item)
{
if(inputString.Contains(item)==true)
{
result = true;
// I want to break here
}
}
));
Edit:
Thanks for the replies, I'm actually reading your book at the minute John :) Just for the record i hit this issue and switched back to a normal foreach loop but I posted this question to see if i missed something.
As others have posted, you can't exit the loop in ForEach.
Are you able to use LINQ? If so, you could easily combine TakeWhile and a custom ForEach extension method (which just about every project seems to have these days).
In your example, however, List<T>.FindIndex would be the best alternative - but if you're not actually doing that, please post an example of what you really want to do.
There is no loop that one has access to, from which to break. And each call to the (anonymous) delegate is a new function call so local variables will not help. But since C# gives you a closure, you can set a flag and then do nothing in further calls:
bool stop = false;
myList.ForEach((a) => {
if (stop) {
return;
} else if (a.SomeCondition()) {
stop = true;
}
});
(This needs to be tested to check if correct reference semantics for closure is generated.)
A more advanced approach would be to create your own extension method that allowed the delegate to return false to stop the loop:
static class MyExtensions {
static void ForEachStoppable<T>(this IEnumerable<T> input, Func<T, bool> action) {
foreach (T t in input) {
if (!action(t)) {
break;
}
}
}
}
Do you have LINQ available to you? Your logic seems similar to Any:
bool any = blackList.Any(s=>inputString.Contains(s));
which is the same as:
bool any = blackList.Any(inputString.Contains);
If you don't have LINQ, then this is still the same as:
bool any = blackList.Find(inputString.Contains) != null;
If you want to run additional logic, there are things you can do (with LINQ) with TakeWhile etc
I don't think there's an elegant way to do it when using the ForEach method. A hacky solution is to throw an exception.
What's preventing you from doing an old fashioned foreach?
foreach (string item in blackList)
{
if (!inputString.Contains(item)) continue;
result = true;
break;
}
If you want a loop, use a loop.
Action allows for no return value, so there's no way the ForEach function could possibly know that you want to break, short of throwing an exception. Using an exception here is overkill.
The only way to "exit" the loop is to throw an exception. There is no "break" style way of exiting the .ForEach method like you would a normal foreach loop.
The ForEach method is not mean to do this. If you want to know if a collection contains an item you should use the Contains method. And if you want to perform a check on all items in a collection you should try the Any extention method.
bool #break = false;
blackList.ForEach(item =>
{
if(!#break && inputString.Contains(item))
{ #break = true;
result = true;
}
if (#break) return;
/* ... */
});
Note that the above will still iterate through each item but return immediately. Of course, this way is probably not as good as a normal foreach.
class Program
{
static void Main(string[] args)
{
List<string> blackList = new List<string>(new[] { "jaime", "jhon", "febres", "velez" });
string inputString = "febres";
bool result = false;
blackList.ForEach((item) =>
{
Console.WriteLine("Executing");
if (inputString.Contains(item))
{
result = true;
Console.WriteLine("Founded!");
}
},
() => result);
Console.WriteLine(result);
Console.ReadLine();
}
}
public static class MyExtensions
{
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action, Func<bool> breakOn)
{
foreach (var item in enumerable)
{
action(item);
if (breakOn())
{
break;
}
}
}
}
Would this work for you:
bool result = null != blackList.Find( item => inputString.Contains(item)) );
blackList.ForEach(new Action<string>(
delegate(string item)
{
if(inputString.Contains(item)==true)
{
result = true;
// I want to break here
return;
}
}
));
if you realy want to exist a loop foreach in a list you could use the exception like this code:
public class ExitMyForEachListException : Exception
{
public ExitMyForEachListException(string message)
: base(message)
{
}
}
class Program
{
static void Main(string[] args)
{
List<string> str = new List<string>() { "Name1", "name2", "name3", "name4", "name5", "name6", "name7" };
try
{
str.ForEach(z =>
{
if (z.EndsWith("6"))
throw new ExitMyForEachListException("I get Out because I found name number 6!");
System.Console.WriteLine(z);
});
}
catch (ExitMyForEachListException ex)
{
System.Console.WriteLine(ex.Message);
}
System.Console.Read();
}
}
hope this help to get other point of view.

Categories