pass a method into another method as a parameter but with parameters - c#

I've posted a similar question (and answered) previously but I've realised I still have a missing piece of the puzzle when passing a method into another method. My question is when passing a method as a parameter how can you include parameters? I've included an example below.
Any help much appreciated.
Many thanks,
Service call
private readonly MemberRepo _memberRepo;
public SomeService()
{
_memberRepo = new MemberRepo();
}
public string GetMembers(int id)
{
// This works, i.e. the RunMethod internally calls the Get method on the repo class - problem: how can I pass the id into the repo Get method?
var result = RunMethod(_memberRepo.Get);
...
return stuff;
}
private string RunMethod(Func<int, string> methodToRun)
{
var id = 10; // this is a hack - how can I pass this in?
var result = methodToRun(id);
..
}
Repository
public class MemberRepo
{
public string Get(int id)
{
return "Member from repository";
}
}
Update
private string RunMethod(Func<int, string> methodToRun)
{
if(id.Equals(1))
{
// Do something
//
var result = methodToRun(id);
..
}

Just pass a second argument to the RunMethod method:
private string RunMethod(Func<int, string> methodToRun, int id)
{
var result = methodToRun(id);
..
}
You can always make id have an optional input as well if needed:
int id= 10

You can pass a lambda function that performs whatever actions you want:
var result = RunMethod(_ => _memberRepo.Get(10));
This makes the int part of the method signature pretty meaningless, so if you have the ability to change your RunMethod() signature, you can do this:
private string RunMethod(Func<string> methodToRun)
{
var result = methodToRun();
..
}
then this:
var result = RunMethod(() => _memberRepo.Get(10));
Update if you need to be able to access the parameter within your RunMethod() method, then just pass it as a separate parameter as TheLethalCoder suggests:
private string RunMethod(Func<int, string> methodToRun, int id)
{
if(id.Equals(1))
{
// Do something
//
var result = methodToRun(id);
..
}
and
var result = RunMethod(memberRepo.Get, 10);

Related

Best way to refactor if statement method

I currently have a method that I'm hard coding the value that needs to be validate in the if statement and then I'm running the method that match the name I'm hardcoding.
Here is my code
public Class Name
public static Dictionary<string, ValueMap> Name1= new Dictionary<string, ValueMap>
public static Dictionary<string, ValueMap> Name2= new Dictionary<string, ValueMap>
public Class compare
public string Test (string sample, string Name)
{
if (sample == "Name1")
{
var results = MethodName (sample, Name.Name1);//call method name Name1
return "";
}
if (sample == "Name2")
{
var results = MethodName (sample, Name.Name2); //call method name Name2
return "";
}
if (sample == "Name3")
{
var results = MethodName (sample, Name.Name3); //call method name Name3
return "";
}
else
{
return ""; ;
}
}
I don't want to add an if statement every time I need to add a different method inside my MethodName or hardcode the values inside my if statement so I was wondering if there is a way I can just look for the method inside the compare class that match the string sample and pass this method to my var results = MethodName (sample, Name.Name3);
Example something like this
public Class Name
public static Dictionary<string, ValueMap> Name1= new Dictionary<string, ValueMap>
public static Dictionary<string, ValueMap> Name2= new Dictionary<string, ValueMap>
public Class Test
string sample = Name1
public string Test (string sample, string Name, Name name)
{
var results = MethodName (sample, Name1 -pass the method inside the compare class that match the name inside the sample string );
return "";
}
else
{
return sample name was not found ; ;
}
One answer is using switch case.
And the second one is use Change of Responsibility pattern.
Chain of responsibility replaces if clauses.

Passing variable from command handler

I have a following method in my command handler that gets variables from another method,im trying to pass those variable into the CreateUser(NewAccount); method but it always comes back as null
public async Task ExecuteAsync(CreateUserAccountCommand command)
{
var result = await _client.CreateUser(GetAccountFrom(command)); // so this line gets the variables from GetAccountFrom(command)
_httpContextAccessor.HttpContext.Items["CreateUserAccountCommand"] = result;
}
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var NewAccount = new Account();
NewAccount.FirstName = command.FirstName;
NewAccount.LastName = command.LastName;
return NewAccount()
}
however when i call CreateUser to pass in the variables into NewAccount thats coming from GetAccountFrom(command) it passes it in as a null
public System.Threading.Tasks.Task<Account> CreateUser(Account NewAccount,)
{
return base.Channel.CreateUser(NewAccount);
}
What am i doing wrong?
You are creating a new instance of NewAccount in your return statement.
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var newAccount = new Account();
newAccount.FirstName = command.FirstName;
newAccount.LastName = command.LastName;
return newAccount; // <- Return the variable
}
You are creating object with new keyword. All you need to do is to return this object from your method with simple call:
return NewAccount;
The way you do it now is that you are returning result of NewAccount() method (whatever it is, apparently null), which is not what you want.
Also you might want to inspect why NewAccount() returns always null.
Your code has many anti patterns but it seems like you have a method somewhere in the base newAccount(); This is why inheritance should be avoided (for beginners and mids)
also the convention for private local variables lowercase.. as to NOT CONFUSE yourself.
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var newAccount = new Account();
newAccount.FirstName = command.FirstName;
newAccount.LastName = command.LastName;
return newAccount;
}
or to completely avoid confusion just do this
private Account GetAccountFrom(CreateUserAccountCommand command)
{
return new Account{
FirstName = command.FirstName,
LastName = command.LastName,
}
}
But to avoid anti-patterns and spaghetti code you should really make an extension method which is much more S.O.L.I.D !
namespace you.company
{
public static CommandExtensions{
public static Account GetAccountFrom(this CreateUserAccountCommand command)
{
return new Account
{
FirstName = command.FirstName,
LastName = command.LastName,
};
}
}

Setup argment matcher with IEnumerable in NSubstitue

I am working on a unit test for a project and I cannot figure out how to get NSubstitute to work the way I would expect it to. The issue I am having is that the code I was to substitute is in a while loop and depending on what is returned from the substituted value determines if the loop continues.
What I would like to do is have Process() return a different result based on what is passed in. I have tried
api.Process(Arg.Is<IEnumerable<int>>(new[] {1,2,3}, Arg.Any<bool>()).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
but it does not seems to work as processingResult comes back null because NSubstitue is not matching the argument.
[Test]
public void TestTwoLoops()
{
var api = Substitute.For<IApi>();
api.Process(/*list containing 1,2,3*/, Arg.Any<bool>()).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
api.Process(/*list containing 30*/, Arg.Any<bool>()).Returns(new List<int>{});
var sut = new WidgetMaker(api);
sut.MakeWidget();
}
public class WidgetMaker
{
public WidgetMaker(IApi api)
{
_api = api;
}
public void MakeWidgets(IEnumerable<int> widgetIds)
{
var idsToProcess = widgetIds.ToList();
while(true)
{
if(!idsToProcess.Any())
{
berak;
}
var processingResult = _api.Process(idsToProcess, false);
if(processingResult.Success)
{
idsToProcess.Clear();
idsToProcess.AddRange(processingResult.IdsNotProcessed);
}
else
{
break;
}
}
}
private IApi _api;
}
As I was writing this question, the answer came to me, but I have a feeling others might find this helpful.
Using the overload that accepts a predicate and using the SequenceEqualExtension method with a parameter of new[] {/values I want to be input/}
api.Process(Arg.Is<IEnumerable<int>>(x => x.SequenceEqual(new[] {1,2,3}, Arg.Any<bool>())).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});

How do I pass an Entity Object to a function in C#

I have a public function that queries against a specific entity. I would like to replicate the function for any table I pass in but don't know how. Here is the working function I want to make dynamic:
public string MaxDepartment()
{
CPLinkEntities _context = new CPLinkEntities();
results = _context.LOG_Departments.Max(t => t.LastUpdated); // hard coded
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
What I would really like to do here is pass in an entity to query against. All entities have a timestamp. Here is what I envision it would look like but doesn't work:
public string MaxDepartment(CPLinkEntities tableName)
{
var results = tableName.Max(t => t.LastUpdated);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
Calling the function from controller then would be:
CPLinkEntities context = new CPLinkEntities();
var tableName = context.LOG_Departments;
var maxDept = cf.MaxDepartment(tableName);
The easiest way to do it without changing any of your existing classes (if you can, see Oleksii's answer) is to manually create the expression tree and have it select the property you want.
public static string MaxDepartment<U>(IQueryable<U> table)
{
var parameter = Expression.Parameter(typeof(U));
var property = Expression.Property(parameter, "LastUpdated");
var lambada = Expression.Lambda<Func<U, byte[]>>(property, parameter);
var results = table.Max(lambada);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
You would call it via
using(CPLinkEntities _context = new CPLinkEntities()) //You forgot to dispose in your original example
{
var max = MaxDepartment(_context.LOG_Departments);
//Do whatever you want with max here.
}
This will fail at runtime if you try to pass in a table that does not have a LastUpdated property.
I think you should mark your entity with an interface like this:
public interface ILastUpdatable
{
byte[] LastUpdated {get;set;}
}
public partial class LOG_Departments : ILastUpdatable
{
}
and then make your method expecting an object of type that implements an interface like this:
public string MaxDepartment<TLastUpdatable>(IQueryable<TLastUpdatable> updatables)
where TLastUpdatable : class, ILastUpdatable
{
var results = updatables.Max(t => t.LastUpdated);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
UPDATE:
Also you would consider to use it as extension method:
public static class MaxUpdatableExtensions
{
public static string MaxDepartment<TLastUpdatable>(this IQueryable<TLastUpdatable> updatables)
where TLastUpdatable : class, ILastUpdatable
{
var results = updatables.Max(t => t.LastUpdated);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
}
and call it like this:
CPLinkEntities _context = new CPLinkEntities();
var results = _context.LOG_Departments.MaxDepartment();

Validating and parsing url parameters in ASP.NET

I'm maintaining a legacy WebForms application and one of the pages just serves GET requests and works with many query string parameters. This work is done in the code-behind and does a lot of this type of check and casting.
protected override void OnLoad(EventArgs e)
{
string error = string.Empty;
string stringParam = Request.Params["stringParam"];
if (!String.IsNullOrEmpty(stringParam))
{
error = "No parameter";
goto LoadError;
}
Guid? someId = null;
try
{
someId = new Guid(Request.Params["guidParam"]);
}
catch (Exception){}
if (!someId.HasValue)
{
error = "No valid id";
goto LoadError;
}
// parameter checks continue on
LoadError:
log.ErrorFormat("Error loading page: {0}", error);
// display error page
}
I'd like to create a testable class that encapsulates this parsing and validation and moves it out of the code-behind. Can anyone recommend some approaches to this and/or examples?
As a first big step, I'd probably create some form of mapper/translator object, like this:
class SpecificPageRequestMapper
{
public SpecificPageRequest Map(NameValueCollection parameters)
{
var request = new SpecificPageRequest();
string stringParam = parameters["stringParam"];
if (String.IsNullOrEmpty(stringParam))
{
throw new SpecificPageRequestMappingException("No parameter");
}
request.StringParam = stringParam;
// more parameters
...
return request;
}
}
class SpecificPageRequest
{
public string StringParam { get; set; }
// more parameters...
}
Then your OnLoad could look like this:
protected override void OnLoad(EventArgs e)
{
try
{
var requestObject = requestMapper.Map(Request.Params);
stringParam = requestObject.StringParam;
// so on, so forth. Unpack them to the class variables first.
// Eventually, just use the request object everywhere, maybe.
}
catch(SpecificPageRequestMappingException ex)
{
log.ErrorFormat("Error loading page: {0}", ex.Message);
// display error page
}
}
I've omitted the code for the specific exception I created, and assumed you instantiate a mapper somewhere in the page behind.
Testing this new object should be trivial; you set the parameter on the collection passed into Map, then assert that the correct parameter on the request object has the value you expect. You can even test the log messages by checking that it throws exceptions in the right cases.
Assuming that you may have many such pages using such parameter parsing, first create a simple static class having extension methods on NamedValueCollection. For example,
static class Parser
{
public static int? ParseInt(this NamedValueCollection params, string name)
{
var textVal = params[name];
int result = 0;
if (string.IsNullOrEmpty(textVal) || !int.TryParse(textVal, out result))
{
return null;
}
return result;
}
public static bool TryParseInt(this NamedValueCollection params, string name, out int result)
{
result = 0;
var textVal = params[name];
if (string.IsNullOrEmpty(textVal))
return false;
return int.TryParse(textVal, out result);
}
// ...
}
Use it as follows
int someId = -1;
if (!Request.Params.TryParseInt("SomeId", out someId))
{
// error
}
Next step would be writing page specific parser class. For example,
public class MyPageParser
{
public int? SomeId { get; private set; }
/// ...
public IEnumerable<string> Parse(NamedValueCollection params)
{
var errors = new List<string>();
int someId = -1;
if (!params.TryParseInt("SomeId", out someId))
{
errors.Add("Some id not present");
this.SomeId = null;
}
this.SomeId = someId;
// ...
}
}

Categories