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.
Related
I have this query where I want to return results if the search string provided yields data from the 'FirstName' and 'LastName' column of my database. They each work individually as I can get results for Firstname = 'john' and LastName = 'doe'. I also want to be able to pass in a search string of 'John doe' and get results. How would I implement this using .net/linq
snippet:
var query = _context.Players.Where(p => p.Firstname.Contains(searchString.ToLower().Trim()) || p.Lastname.Contains(searchString.ToLower().Trim()));
use Split function like the following:
var parts = searchString.Split();
snippet: var query = _context.Players.Where(
p => p.Firstname.Contains(parts[0].ToLower().Trim())
|| p.Lastname.Contains(parts[1].ToLower().Trim()));
Extracted from the official docs:
If the separator parameter is null or contains no characters, white-space characters are assumed to be the delimiters.
Separating the input data is also convenient
var parts = searchString.Split();
var partOne = parts[0].ToLower().Trim();
var partTwo = parts[1].ToLower().Trim()
var query = _context.Players.Where(
p => p.Firstname.Contains(partOne)
|| p.Lastname.Contains(partTwo));
Created an extension method class to isolate the functional parts of search algo. This is based on pattern matching algo. You can try this one once.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
static class Extensions
{
public static void Sanitize(this string item)
{
Regex rgx = new Regex("[^a-AA-Z0-9 -]");
item = rgx.Replace(item, " ");
}
public static string GetPipedString(this string item)
{
StringBuilder builder = new StringBuilder();
item.Split(' ').ToList().ForEach(x => builder.Append('|').Append(x));
builder.Remove(0, 1);
return builder.ToString();
}
public static IEnumerable<Person> FindPlayers(this IEnumerable<Person> persons, string searchKey)
{
searchKey.Sanitize();
string pattern = string.Format(#"^?:{0}\w*$", searchKey.GetPipedString());
return persons.Where(x => Regex.IsMatch(
string.Join(string.Empty,
new List<string>() { x.FirstName, x.LastName }),
pattern,
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace));
}
}
class Program
{
static void Main(string[] args)
{
/* Assuming peoples is the IEnumerable<Person>.
Anyways there is an explicit sanitization of the string to remove the non alphanum characters*/
var items = peoples.FindPlayers("ANY DATA SPACE SEPARATED").ToList();
}
}
With "Best Way" I mean, maybe, without many If, clean code.
I have a function that receives as parameters (string currentVersion, string action)
and it should return a string versionToBe = "";
For action = "installOldVersion"
-------------if "currentVersion"----------------: -------------OldversionToInstall--------------
"windows10(pro)", "windows10(pro)(education)" : "windows81(pro)"
"windows10(enterprise)", "windows10(enterpise)(lstb)" : "windows81(enterprise)"
"windows7(home)", "windows7(home)(basic)", "windows7(basic)", "windows7": "windowsVista(starter)"
"windowsXP(starter)", "windowsXP(starter)(home)", "windowsXP(home)", "windowsXP": "windows2000(professional)"
"windowsNT(workstation)", "windowsNT": "windows95(sp1)"
For action = "installNewVersion"
-------------if "currentVersion"----------------: -------------NewVersionToInstall--------------
"windows81(pro)", "windows81(pro)(education)" : "windows10(pro)"
"windows81(enterprise)", "windows81(enterprise)(education)" : "windows10(enterprise)"
"windowsVista(starter)", "windowsVista(starter)(package)", "windowsVista(package)", "windowsVista": "windows7(home)"
"windowsVista(starter)", "windowsVista(starter)(praok)", "windowsVista(praok)", "windowsVista": "windowsXP(starter)"
"windows95(sp1)", "windows95(sp1)(versionE)", "windows95": "windowsNT(workstation)"
So,for example, everytime the string name comes like: "windows10(pro)" or "windows10(pro)(education)" it should return: "windows81(pro)".
I know this can get done with lots of if like:
if (version.Equals("windows10(pro)") || version.Equals("windows10(pro)(education)"))
{
versionToBe = "windows81(pro)";
}
and the same for the rest of them, anding with 10 If statements in Total.
But If there's a better way to do it, I'd want to know.
Another restriction, or other thing to consider:
if the action is "installOldVersion", versionToBe is OldversionToInstall,
and if the action is "installNewVersion", versionTobe would be NewVersionToInstall.
You could create a list of objects with CurrentVersion, Old Version and New Version and then extract the one you want from the list.
Example Instruction Class Definition
public class VersionInformation
{
public string CurrentVersion {get; set;}
public string NewVersion {get; set;}
public string OldVersion {get; set;}
}
then in your program, have a list of them, either hard coded or loaded from file or whatever datastore you want and do your version check as follows:
private List<VersionInformation> _versionInformation = //Load your list from wherever;
public void DoVersionCheck(string version)
{
var currentversionInfo = _versionInformation.Single(x=> x.CurrentVersion == version);
//Do Whatever you want with the upgrades and downgrades here based on whatever action you are doing
}
Set yourself up a dictionary and perform a lookup.
As an exercise for the reader:
You could drive the dictionary contents from some configuration or other...even from a database if you want.
You'd presumably want to set up your dictionary as a static and initialize it only once.
You'll want some handling for when there is no dictionary entry - you don't specify a default in your question.
Dictionary, string> ActionMatrix = new Dictionary, string>();
ActionMatrix.Add(Tuple.Create ("windows10(pro)", "installOldVersion"), "windows81(pro)");
ActionMatrix.Add(Tuple.Create ("windows10(pro)(education)", "installOldVersion"), "windows81(pro)");
ActionMatrix.Add(Tuple.Create ("windows10(enterprise)", "installOldVersion"), "windows81(enterprise)");
ActionMatrix.Add(Tuple.Create ("windows10(enterpise)(lstb)", "installOldVersion"), "windows81(enterprise)");
// etc
ActionMatrix.Add(Tuple.Create("windows81(pro)", "installNewVersion"), "windows10(pro)");
ActionMatrix.Add(Tuple.Create("windows81(pro)(education)", "installNewVersion"), "windows10(pro)");
ActionMatrix.Add(Tuple.Create("windows81(enterprise)", "installNewVersion"), "windows10(enterprise)");
ActionMatrix.Add(Tuple.Create("windows10(enterpise)(education)", "installNewVersion"), "windows10(enterprise)");
// etc
public string VersionToBe (string currentVersion, string action)
{
return ActionMatrix[Tuple.Create(currentVersion, action)];
}
A simple object with it's own list should do the trick and is visually better to follow.
public class VersionData
{
private static List<VersionData> VersionDatas { get; set; } = new List<VersionData>()
{
new VersionData( "OldversionToInstall", new [] {"windows10(pro)", "windows10(pro)(education)" }.ToList(), "windows81(pro)" ),
new VersionData( "OldversionToInstall", new [] {"windows10(enterprise)", "windows10(enterpise)(lstb)" }.ToList(), "windows81(enterprise)" )
};
public string Action { get; set; } = "";
public List<string> CurrentVersions { get; set; } = new List<string>();
public string Version { get; set; } = "";
public VersionData(string action, List<string> currentVersions, string version)
{
Action = action;
CurrentVersions = currentVersions;
Version = version;
}
public static string GetVersion(string action, string currentVersion)
{
return VersionDatas.FirstOrDefault(o => o.Action == action && o.CurrentVersions.Any(x => x == currentVersion)).Version;
}
}
and to call it's as simple as :
var oldVersion = VersionData.GetVersion("OldversionToInstall", "windows10(enterpise)(lstb)");
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);
I would like some way to hard code information in C# as follows:
1423, General
5298, Chiro
2093, Physio
9685, Dental
3029, Optics
I would like to then refer to this data as follows:
"The description for category 1423 is " & MyData.GetDescription[1423]
"The id number for General is " & MyData.GetIdNumber("General")
What would be the best way to do this in C#?
Well you could use Tuple<int, string> - but I'd suggest creating a class to store the two values:
public sealed class Category
{
private readonly int id;
public int Id { get { return id; } }
private readonly string description;
public string Description { get { return description; } }
public Category(int id, string description)
{
this.id = id;
this.description = description;
}
// Possibly override Equals etc
}
Then for lookup purposes, you could either have a Dictionary<string, Category> for description lookups and a Dictionary<int, Category> for ID lookups - or if you were confident that the number of categories would stay small, you could just use a List<Category>.
The benefits of having a named type for this over using just a Tuple or simple Dictionary<string, int> and Dictionary<int, string> are:
You have a concrete type you can pass around, use in your data model etc
You won't end up confusing a Category with any other data type which is logically just an int and a string
Your code will be clearer to read when it uses Id and Description properties than Item1 and Item2 from Tuple<,>.
If you need to add another property later, the changes are minimal.
You can use a Dictionary<TKey, TValue>:
var items = new Dictionary<int, string>();
items.Add(1423, "General");
...
var valueOf1423 = items[1423];
var keyOfGeneral = items.FirstOrDefault(x => x.Value == "General").Key;
The example above will throw an exception if there's no item with value "General". To prevent this you could wrap the Dictionary in a custom class and check if the entry exists and returns whatever you need.
Note that the value is not unique, a Dictonary allows you to store the same values with different keys.
A wrapper class could look something like this:
public class Category {
private Dictionary<int, string> items = new Dictionary<int,, string>();
public void Add(int id, string description) {
if (GetId(description <> -1)) {
// Entry with description already exists.
// Handle accordingly to enforce uniqueness if required.
} else {
items.Add(id, description);
}
}
public string GetDescription(int id) {
return items[id];
}
public int GetId(string description) {
var entry = items.FirstOrDefault(x => x.Value == description);
if (entry == null)
return -1;
else
return entry.Key;
}
}
I am not sure what the best and simplest way to do this, so any advice is appreciated.
I want to get all the fields on any/all/single domain entity class and add prefix/remove prefix dynamically when calling a particular method.
For example, I have entities such as:
public class Shop
{
public string TypeOfShop{get;set}
public string OwnerName {get;set}
public string Address {get;set}
}
public class Garage
{
public string Company {get;set}
public string Name {get;set}
public string Address {get;set}
}
and so on...
I want to get a list of the properties with a prefix:
public Class Simple
{
public class Prop
{
public string Name{get;set;}
public string Value{get;set;}
}
public ICollection list = new List<Prop>();
//set all prop
public void GetPropertiesWithPrefix(Garage mygarage, string prefix)
{
list.Add(new Prop{Name = prefix + "_Company", Value = mygarage.Company});
//so on... upto 50 props...
}
}
//to get this list I can simple call the list property on the Simple class
When reading each field I am using a switch statement and setting the value.
//Note I return a collection of Prop that have new values set within the view,lets say
//this is a result returned from a controller with the existing prop names and new values...
public MyGarage SetValuesForGarage(MyGarage mygarage, string prefix, ICollection<Prop> _props)
{
foreach (var item in _prop)
{
switch(item.Name)
{
case prefix + "Company":
mygarage.Company = item.Value;
break;
//so on for each property...
}
}
}
Is there a better, simpler or more elegant way to do this with linq or otherwise?
You could store props in a dictionary, then have:
mygarage.Company = _props[prefix + "_Company"];
mygarage.Address = _props[prefix + "_Address"];
//And so on...
in your SetValuesForGarage method instead of a loop with a switch inside.
EDIT
For more info on using Dictionary see MSDN.
You can define list something like:
Dictionary<string, string> list = new Dictionary<string, string>();
And have something like the following in your GetPropertiesWithPrefix method:
list.Add(prefix + "_Company", mygarage.Company);
list.Add(prefix + "_Address", mygarage.Address);
//And so on...
This would eliminate your Prop class.
Maybe the following method works for you. It takes any object, looks up its properties and returns a list with your Prop objects, each for every property.
public class PropertyReader
{
public static List<Prop> GetPropertiesWithPrefix(object obj, string prefix)
{
if (obj == null)
{
return new List<Prop>();
}
var allProps = from propInfo
in obj.GetType().GetProperties()
select new Prop()
{
Name = prefix + propInfo.Name,
Value = propInfo.GetValue(obj, null) as string
};
return allProps.ToList();
}
}