Strange control flow - c#

I'm working on a framework in C# that will depend on pluggable components implemented as classes inheriting a base class. In order to make the components as simple as possible, I am working on some weird control flow.
The base class includes a static method RunStep(parameter). This method is called a number of times by the inheriting class, and each time it is called a condition is checked. If this condition happens to be false, I want the calling method to stop and return. A simplified working version of the code would be:
Base class:
class MyBase
{
private static object RunStep(string parameter)
{
if(SomeFunction(parameter))
return SomeOtherFunction(parameter);
else
return null;
}
}
Inheriting class:
class MyInheritor
{
public void Run()
{
object result = RunStep("mystring1");
if(null != result)
{
//perform some logic on result
result = RunStep("mystring2");
if(null != result){
//perform some different logic on result
RunStep("mystring3");
}
}
}
}
What I am wondering is whether it is possible to do something in the base class so that I can simplify the inheriting class to this:
class MyInheritor2
{
public void Run()
{
object result = RunStep("mystring1");
//perform some logic on result
result = RunStep("mystring2");
//perform some different logic on result
result = RunStep("mystring3");
}
}
}
I would put the parameters in a list and loop over them, but there is logic that needs to happen after each call to the RunStep method, and the logic is different each time. This takes a loop off the table. Also note that the logic between the RunStep calls accesses properties on result, so it crashes without the null checks.
It may seem like a trivial thing, but there may be thousands of these Inheriting classes and simplifying them is a big deal.

Let the base class to control the execution flow:
class Base
{
private readonly List<Tuple<string, Action>> steps = new List<Tuple<string, Action>>();
protected void RegisterStep(string parameter, Action someLogic)
{
steps.Add(Tuple.Create(parameter, someLogic));
}
protected void Run()
{
foreach (var step in steps)
{
var result = RunStep(step.Item1);
if (result == null)
{
break;
}
// perform some logic
step.Item2();
}
}
private object RunStep(string parameter)
{
// some implementation
return null;
}
}
class Derived : Base
{
public Derived()
{
RegisterStep("1", () => { });
RegisterStep("2", () => { });
RegisterStep("3", () => { });
// etc
}
}

There's no way to make a function call exit the calling function except for throwing an Exception, which you shouldn't do.
What you can do to make your code cleaner is to invert the cases.
object result = RunStep("mystring1");
if (result == null) return;
result = RunStep("mystring2");
if (result == null) return;
result = RunStep("mystring3");
if (result == null) return;

Related

Nunit: Testing legacy code (private void) method

I have been tasked with building unit tests for a bunch of legacy code. The specific task/goal for the below method is to test that the messageProcessor.ProcessCustomerPhoneContactInfo(currentPhoneContact) method is being called. I am also posting the test stub I have written so far but I would appreciate some direction because I think I am going down a rabbit hole here. How can I fill in the blanks on my test?
Method being tested:
private void logPhoneCallDialog_SaveContact(Contact currentPhoneContact)
{
if (currentPhoneContact != null)
{
RefreshRenewalActivity();
if (currentPhoneContact.TypeId == ResultType.TookAppointment)
}
NotifyServerOfActivity();
ApplyAppointmentFilters();
this.Activate();
var messageProcessor = new MessageProcessor();
messageProcessor.ProcessCustomerPhoneContactInfo(currentPhoneContact);
}
Test:
[TestFixture, RequiresSTA]
class BucketBrowserTest
{
[Test]
public void logPhoneCallDialog_SaveContact()
{
//Arrange
//Act
//Assert
}
}
Method that calls above method
private void ShowPhoneCallLoggerDialog()
{
PhoneCallLoggerDialog dialog = new PhoneCallLoggerDialog(CurrentCustomer, CurrentBucket.BucketTypeId);
dialog.Owner = this;
dialog.SaveContact += new PhoneCallLoggerDialog.SaveContactHandler(logPhoneCallDialog_SaveContact);
dialog.ShowDialog();
}
Event Handler for calling method
public delegate void SaveContactHandler(PhoneContact currentPhoneContact);
public event SaveContactHandler SaveContact;
Based on the additional information you've supplied, I'm going to outline my assumptions before describing a possible solution:
You're able to safely construct an instance of this class, without calling anything out of process
Calling logPhoneCallDialog_SaveContact(), won't trigger side effects that prevent it from being tested
When refactoring legacy code, you often have to make design choices that you would normally avoid. This can include:
Testing implementation details
Making methods public or internal
Adding light abstractions that simply facilitate testing
In order to get a test around this, you're going to have to do at least one of those things.
Firstly, make logPhoneCallDialog_SaveContact public:
public void logPhoneCallDialog_SaveContact(Contact currentPhoneContact)
{
// same body as before
}
Next, extract a method that holds the entire body of the first one, to end up with this:
public void logPhoneCallDialog_SaveContact(Contact currentPhoneContact)
{
SaveContact(currentPhoneContact);
}
private void SaveContact(Contact currentPhoneContact)
{
if (currentPhoneContact != null)
{
RefreshRenewalActivity();
// This code from your example doesn't compile.
if (currentPhoneContact.TypeId == ResultType.TookAppointment)
}
NotifyServerOfActivity();
ApplyAppointmentFilters();
this.Activate();
var messageProcessor = new MessageProcessor();
messageProcessor.ProcessCustomerPhoneContactInfo(currentPhoneContact);
}
Make the new method public:
public void SaveContact(Contact currentPhoneContact)
{
// same body as before
}
If you haven't already, extract an interface for MessageProcessor:
public interface IMessageProcessor
{
ProcessCustomerPhoneContactInfo(Contact currentPhoneContact);
}
public class MessageProcessor : IMessageProcessor
{
public void ProcessCustomerPhoneContactInfo(Contact currentPhoneContact)
{
// implementation
}
}
Now modify the methods like so:
public void logPhoneCallDialog_SaveContact(Contact currentPhoneContact)
{
var messageProcessor = new MessageProcessor();
SaveContact(currentPhoneContact, messageProcessor);
}
public void SaveContact(
Contact currentPhoneContact,
IMessageProcessor messageProcessor)
{
if (currentPhoneContact != null)
{
RefreshRenewalActivity();
if (currentPhoneContact.TypeId == ResultType.TookAppointment)
}
NotifyServerOfActivity();
ApplyAppointmentFilters();
this.Activate();
messageProcessor.ProcessCustomerPhoneContactInfo(currentPhoneContact);
}
Now write your unit tests against SaveContact, mocking IMessageProcessor, instead of against logPhoneCallDialog_SaveContact.
Edit
Here's an example, as requested. It's been a while since I've used Moq - which was in your original question - so the syntax may not be quite right, but something like this:
[Test]
public void SavesContact()
{
// Arrange
var contact = new Contact();
var messageProcessor = new Mock<IMessageProcessor>();
var subject = // whatever class contains the logPhoneCallDialog_SaveContact method
// Act
subject.SaveContact(contact, messageProcessor.Object);
// Assert
messageProcessor.Verify(x => x.ProcessCustomerPhoneContactInfo(contact), Times.Once());
}
Also test the case where contact is null.
With the code as it stands, you cannot mock out the messageProcessor, but with a few changes, you could:
IMessageProcessorFactory _messageProcessorFactory;
public TheConstructor(IMessageProcessorFactory processorFactory)
{
_messageProcessorFactory = processorFactory;
}
private void logPhoneCallDialog_SaveContact(Contact currentPhoneContact)
{
if (currentPhoneContact != null)
{
RefreshRenewalActivity();
if (currentPhoneContact.TypeId == ResultType.TookAppointment)
}
NotifyServerOfActivity();
ApplyAppointmentFilters();
this.Activate();
var messageProcessor = _messageProcessorFactory.Create();
messageProcessor.ProcessCustomerPhoneContactInfo(currentPhoneContact);
}
Then you can Moq/Mock the interface and find out if the function was called.

Controlling service flow from the Caller method

Is it correct to control how the service works from the caller of this service? I had such a problem today, and don't know if my solution is good or not. Hope someone more advanced can give me a feedback. Here is my problem:
I have got a service with method Foo:
public class Service
{
public int? Foo(int? number, bool throwException)
{
int? result = number;
if (result == null)
{
var result = ...
if (result == null && throwException)
{
throw new Exception("ZZZZ");
}
}
return result
}
}
Now in Caller class I got 2 methods where I invoke this Service:
public class Caller
{
public void Test1()
{
...
Service.Foo(number, TRUE);
...
}
public void Test2()
{
...
Service.Foo(number, FALSE);
...
}
As you can see for Test1 im sending flag throwException TRUE, and for Test2 FALSE, is it good practice to control how the Service's flow go from the Caller's methods?
That's what i tried to avoid:
public class Caller
{
public void Test1()
{
var a = Service.Foo1();
if (a == something)
{
throw ARgumentException("ZZZ");
}
var b = Service.Foo2();
if (b == something2)
{
throw ArgumentException("ZZZ2");
}
...
}
}
It is not recommended by the Clean Code book to use "flag" (boolean) arguments. In this case you should make two methods in the service, one FooRequired() and one FooOrDefault(), or something like that.

Update a specific column of a List <T>

First they forgive me for my English since it is not my native language.
I have a method which receives a generic list List<T>. what I want is to foreach through the whole list and be able to update a column called Eliminated of each class T and which is of the boolean type, is it possible to do? can anybody help me.
This is what I have so far:
// Delete (Change status delete = true)
public void Delete<T>(List<T> data)
{
if (data != null)
{
data.ForEach(x =>
{
...
});
}
}
Thanks in advance!
Instead of T i would use an interface, because otherwise in the foreach you cannot access the property Eliminated.
Here the interface:
interface IExample {
bool IsEliminated { get; set; }
}
and here the method with the ForEach loop.
public void Delete<T>(List<T> data) where T : IExample
{
if (data != null)
{
data.ForEach(x =>
{
x.Eliminated = true;
});
}
}
If you want a generic method to update a list of any type, you could do something like this:
public void Update<T>(List<T> data, Action<T> func)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
data.ForEach(func);
}
Note I've change the null check to throw if you pass in a null list. You could just return here instead, this way eliminates some nesting.
This allows you to pass in an action that you apply to every item in a collection. You would use it like this:
var data = new List<YourClass> = GetData();
Update(data, item => item.Eliminated = true);
Your T has no property called Eliminated. Your compiler cannot guarantee that any T you will ever use with this method will have that member, so you are not allowed to compile it that way.
You could put a constraint on your T that allows the compiler to make sure the property exists:
public interface Eliminatable
{
bool Eliminated { get; set; }
}
public void Delete<T>(List<T> data) where T : Eliminatable
{
if (data != null)
{
data.ForEach(x => { x.Eliminated = true; });
}
}
Or (and some may say this is a hack) you can just trust your users that they will in fact pass something as T that confirms to your pattern:
public void Delete<T>(List<T> data)
{
if (data != null)
{
data.ForEach(x => { dynamic d = x; d.Eliminated = true; });
}
}
Now this will fail if the property is not there. At runtime. Not nice. But it "works".

A way to call method once

I have the following, I want to move the setting of webDB and item outside of the following public string method which is an example how would I go about doing this.
public string Width
{
get
{
if (webDB != null)
{
webDB = Sitecore.Configuration.Factory.GetDatabase("web");
Sitecore.Data.Items.Item item = webDB.Items[StartItem];
if (item != null)
{
Sitecore.Data.Fields.Field field = item.Parent.Fields["Identity_Page_Width"];
if (!String.IsNullOrEmpty(field.Value))
{
return field.Value;
}
else
{
return "964"; // returns default pixel width if Identity_Page_Width is not defined, or is null
}
}
else
{
return "964"; // If item is not found return default width.
}
}
else
{
return "964";
}
}
}
This is how I have attempted to separate it:
public void GetConfiguration()
{
if (webDB != null)
{
webDB = Sitecore.Configuration.Factory.GetDatabase("web");
if (item != null)
{
item = webDB.Items[StartItem];
}
}
}
but I get stuck with trying to run the method within the code I get method must have a return type.
I then want to run this GetConfiguration only ONCE within the class somewhere so all methods don't need to contact the database and items data more then they have to.
I could do MyClass class = New MyClass; Class.GetConfiguration(); but I don't want future coders to have to know this needs to be instantiated every time to continue. I would rather remove that dependency.
If webDB being instantiated is critical for most/all functionality of the class, consider initializing it in the instance constructor (if non-static), or a static constructor (if static)
Otherwise, I would create a
private InitializeWebDB(){if(webDB == null){...}}
which you can call within your class when needed.
Further, on properties which require access to this, I would use methods instead such as:
public String GetWidth(){InitializeDB(); ...}
which implies more logic/overhead than a simple property field return.
Your code can be improved in a few ways. But to answer your question -
Why not use a static c'tor? This way you ensure it only runs once
public class SomeClass
{
static SomeClass()
{
if (webDB != null)
// etc. etc.
}
... // other code
}
Making the webDB variable static would impose that it will only be null in your first Property call.
private static <whatevertype> webDB;
private static <whatevertype> item;
public void GetConfiguration()
{
if (webDB == null)
{
webDB = Sitecore.Configuration.Factory.GetDatabase("web");
if (item != null)
item = webDB.Items[StartItem];
}
}

Determining if a method calls a method in another assembly containing a new statement and vice-versa

I want to write a rule that will fail if an object allocation is made within any method called by a method marked with a particular attribute.
I've got this working so far, by iterating up all methods calling my method to check using CallGraph.CallersFor(), to see if any of those parent methods have the attribute.
This works for checking parent methods within the same assembly as the method to be checked, however reading online, it appears that at one time CallGraph.CallersFor() did look at all assemblies, however now it does not.
Question: Is there a way of getting a list of methods that call a given method, including those in a different assembly?
Alternative Answer: If the above is not possible, how do i loop through every method that is called by a given method, including those in a different assembly.
Example:
-----In Assembly A
public class ClassA
{
public MethodA()
{
MethodB();
}
public MethodB()
{
object o = new object(); // Allocation i want to break the rule
// Currently my rule walks up the call tree,
// checking for a calling method with the NoAllocationsAllowed attribute.
// Problem is, because of the different assemblies,
// it can't go from ClassA.MethodA to ClassB.MethodB.
}
}
----In Assembly B
public var ClassAInstance = new ClassA();
public class ClassB
{
[NoAllocationsAllowed] // Attribute that kicks off the rule-checking.
public MethodA()
{
MethodB();
}
public MethodB()
{
ClassAInstance.MethodA();
}
}
I don't really mind where the rule reports the error, at this stage getting the error is enough.
I got round this issue by adding all referenced dlls in my FxCop project, and using the code below, which builds a call tree manually (it also adds calls for derived classes to work round another problem i encountered, here.
public class CallGraphBuilder : BinaryReadOnlyVisitor
{
public Dictionary<TypeNode, List<TypeNode>> ChildTypes;
public Dictionary<Method, List<Method>> CallersOfMethod;
private Method _CurrentMethod;
public CallGraphBuilder()
: base()
{
CallersOfMethod = new Dictionary<Method, List<Method>>();
ChildTypes = new Dictionary<TypeNode, List<TypeNode>>();
}
public override void VisitMethod(Method method)
{
_CurrentMethod = method;
base.VisitMethod(method);
}
public void CreateTypesTree(AssemblyNode Assy)
{
foreach (var Type in Assy.Types)
{
if (Type.FullName != "System.Object")
{
TypeNode BaseType = Type.BaseType;
if (BaseType != null && BaseType.FullName != "System.Object")
{
if (!ChildTypes.ContainsKey(BaseType))
ChildTypes.Add(BaseType, new List<TypeNode>());
if (!ChildTypes[BaseType].Contains(Type))
ChildTypes[BaseType].Add(Type);
}
}
}
}
public override void VisitMethodCall(MethodCall call)
{
Method CalledMethod = (call.Callee as MemberBinding).BoundMember as Method;
AddCallerOfMethod(CalledMethod, _CurrentMethod);
Queue<Method> MethodsToCheck = new Queue<Method>();
MethodsToCheck.Enqueue(CalledMethod);
while (MethodsToCheck.Count != 0)
{
Method CurrentMethod = MethodsToCheck.Dequeue();
if (ChildTypes.ContainsKey(CurrentMethod.DeclaringType))
{
foreach (var DerivedType in ChildTypes[CurrentMethod.DeclaringType])
{
var DerivedCalledMethod = DerivedType.Members.OfType<Method>().Where(M => MethodHidesMethod(M, CurrentMethod)).SingleOrDefault();
if (DerivedCalledMethod != null)
{
AddCallerOfMethod(DerivedCalledMethod, CurrentMethod);
MethodsToCheck.Enqueue(DerivedCalledMethod);
}
}
}
}
base.VisitMethodCall(call);
}
private void AddCallerOfMethod(Method CalledMethod, Method CallingMethod)
{
if (!CallersOfMethod.ContainsKey(CalledMethod))
CallersOfMethod.Add(CalledMethod, new List<Method>());
if (!CallersOfMethod[CalledMethod].Contains(CallingMethod))
CallersOfMethod[CalledMethod].Add(CallingMethod);
}
private bool MethodHidesMethod(Method ChildMethod, Method BaseMethod)
{
while (ChildMethod != null)
{
if (ChildMethod == BaseMethod)
return true;
ChildMethod = ChildMethod.OverriddenMethod ?? ChildMethod.HiddenMethod;
}
return false;
}
}
Did you give it a try in this way,
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
object [] items = methodBase.GetCustomAttributes(typeof (NoAllocationsAllowed));
if(items.Length > 0)
//do whatever you want!

Categories

Resources