Reputation: 4645
I'm using C# 4.6.2, though could upgrade to 4.7.2 if it's possible there.
In many places in our code we have a loop with wait statements to check for a specific value when a function is called, wait and retry if it's not what we wanted until a maximum number of retries.
I'd like to abstract this out, but the only implementation I can think of requires you pass in a method with a variable number of arguments of variable types, which after much searching of Google appeared to not be possible about 5 years ago. There has been many improvements to C# since then, so
The sort of thing I'm looking for is:
public bool GenericLoopWait(int maxWaitSeconds, int waitMsPerIteration,??? DoSomething,object expectedResult,...)
int maxRetries = maxWaitSeconds*1000/waitMsPerIteration;
SomeType result=null;
for(int i=0; i<maxRetries; i++){
result = DoSomething(...);
if(result==expectedResult) break;
Thread.Sleep(waitMsPerIteration);
}
return result==expectedResult
}
And then both of these would work:
GenericLoopWait(5,500,Browser.Webdriver.FindElements(selector).Any(),true);
GenericLoopWait(5,500,Api.GetSpecificObject(api,objectName),"expectedOutcome");
Upvotes: 2
Views: 292
Reputation: 62238
You could use generics and Func
and wrap the actual calls parameters when you call through to the method.
public bool GenericLoopWait<T>(int maxWaitSeconds, int waitMsPerIteration, Func<T> DoSomething, T expectedResult = default(T))
{
int maxRetries = maxWaitSeconds * 1000 / waitMsPerIteration;
T result = default(T);
for (int i = 0; i < maxRetries; i++)
{
result = DoSomething();
if (expectedResult.Equals(result)) break;
Thread.Sleep(waitMsPerIteration);
}
return expectedResult.Equals(result);
}
Calling code:
GenericLoopWait(5, 500, () => Browser.Webdriver.FindElements(selector).Any(), true);
GenericLoopWait(5, 500, () => Api.GetSpecificObject(api,objectName), "expectedOutcome")
Upvotes: 7
Reputation: 16991
The general pattern is to create a "Wrapper" method that accepts an Action
or a Func
as a parameter. Your wrapper can do it's own logic, and Invoke
the parameter at the correct time.
As a simple generic example:
public void MethodWrapper(Action action)
{
Console.WriteLine("begin");
action.Invoke();
Console.WriteLine("end");
}
You could then do this:
void Main()
{
var a = 1;
var b = 2;
MethodWrapper(() => DoSomething(a));
MethodWrapper(() => DoSomethingElse(a,b));
}
public void DoSomething(int a)
{
Debug.WriteLine($"a={a}");
}
public void DoSomethingElse(int a, int b)
{
Debug.WriteLine($"a={a}, b={b}");
}
To generate this output:
begin
a=1
end
begin
a=1, b=2
end
For your specific case, your wrapper could take additional parameters specifying things like number of retries, time between calls, or acceptance criteria.
Upvotes: 0