Used Named Optional Parameters for Method - c#

I have a method where I have several optional boolean parameters, different properties of an object will be given a value based on which parameters are true.
Here is the method for context:
public static AutoPatientLookup InitializeTestPatientInfo(bool SSN = false, bool PatientNumber = false, bool Gender = false)
{
AutoPatientLookup TestAPIParameters = new AutoPatientLookup();
TestAPIParameters.FirstName = "First";
TestAPIParameters.LastName = "Last";
TestAPIParameters.DOB = "4/9/1953";
TestAPIParameters.PracticeID = 11071;
if (SSN)
{
TestAPIParameters.SSN = 000010281;
}
if (PatientNumber)
{
TestAPIParameters.PatientNumber = 458;
}
if (Gender)
{
TestAPIParameters.Gender = "F";
}
return TestAPIParameters;
}
However, sometimes I want the second or third boolean parameter to be true but I'm unable to designate that as the parameter I want to switch without explicitly stating true or false for the preceding parameters.
This if I want to initialize an AutoPatientLookup object that has a value for its gender property, I would have to call it like this:
InitializeTestPatientInfo(false,false,true);
I tried something along the lines of
InitializeTestPatientInfo(Gender = true);
and
InitializeTestPatientInfo(bool Gender = true);
but nothing seems to work. Is there a correct syntax for accomplishing for what I'm attempting? Even though the initialization syntax isn't very inconvenient when there are only three boolean parameters this could be more applicable if there are dozens.

The syntax you want to use is:
InitializeTestPatientInfo(Gender: true);

Try
InitializeTestPatientInfo(Gender: true);

You can name your parameter that you are assigning:
Do this instead
InitializeTestPatientInfo(Gender: true);

Related

Querystring to optional arguments

I have a querystring with a number of optional values eg.
/filter?location=scotland&minprice=100&maxprice=500
I have a filter method with a number of optional arguments
public List<result> Filter(
bool isVisible = false,
string location = null,
int? minPrice = null,
int? maxPrice = null,
)
I would like to use the querystring values as arguments on the filter method, but I can't think of a good way to do this.
The best way I can come up with is to use ?: conditions for each argument
var results = Filter(
(Request.QueryString["isvisible"] != null ? Request.QueryString["isvisible"] == "true" : false)
and so on...
but using this method, if a particular querystring value hasn't been set, I have to pass in a default value, but I don't want to pass in a default, I want defaults to be set from within the filter method.
Is there a way to do this? Or is there a better way to achieve the same thing?
Sounds like you just need to map the defaults.
There are actually two "interfaces" here: the interface from the caller to the Filter() method and the interface from the Filter() method to the data source. They don't have to have the same defaults.
public List<Whatever> Filter(string criteria1 = null, string criteria2 = null)
{
criteria1 = criteria1 ?? SYSTEM_DEFAULT_FOR_CRITERIA1;
criteria2 = criteria2 ?? SYSTEM_DEFAULT_FOR_CRITERIA2;
return _dataSource.GetData(criteria1, criteria2);
}

GetField() return null without reason

my GetField or GetProprety function returns null and I don't understand why
So this is a small code which returns this problem
private void Application_WindowSelectionChange(MSProject.Window Window, MSProject.Selection sel, object selType)
{
MSProject.Task task;
string FieldName = Application.ActiveSelection.FieldNameList[1];
if (sel.Tasks != null)
{
task = sel.Tasks[1];
var typeValue = task.GetType();
var typeProp = typeValue.GetField(FieldName);
var typeGetValue = typeProp.GetValue(task);
}
}
So task is never null as it's a condition for my if.
typeValue gets a value {Name = "__ComObject" FullName = "System.__ComObject"},
but my typeProp and TypeGetvalue are null.
my GetField or GetProprety function returns null
This is because the GetField method takes a long (msdn reference), but you are feeding it a string. Instead of using the FieldNameList property, which returns the name of the field, use FieldIDList which returns the field ID.
Note: use the ActiveCell.Text property to get the value of the first field for the first task in the selection.
Reflection on COM objects do not work as with .NET classes.
As I do not have MS Access installed I can not prove following code.
string FieldName = Application.ActiveSelection.FieldNameList[1];
if (sel.Tasks != null)
{
task = sel.Tasks[1];
long projectField = FieldNameToFieldConstant(FieldName, pjProject);
string value = task.GetField(projectField);
}
Sources:
https://msdn.microsoft.com/en-Us/VBA/Project-VBA/articles/task-getfield-method-project
https://msdn.microsoft.com/en-Us/VBA/Project-VBA/articles/pjfield-enumeration-project
https://msdn.microsoft.com/en-Us/VBA/Project-VBA/articles/application-fieldnametofieldconstant-method-project

Pass multiple parameters, choose one that's been passed in c#

Calling my method:
fpt.CouttsPositionSection.AssetClassAssets.Add(dataGenerator.GenerateFPTAssetClassAsset(fpt,*different parameter*));
My method:
public FPTAssetClassAsset GenerateFPTAssetClassAsset(FPT fpt, *4 parameters, with different variable names*)
{
FPTStaticDataAssetClassAssetlist = db.FPTStaticDataRatedFinancialAssetBase.OfType<FPTStaticDataAssetClassAsset>().Where(e => e.FORATExcelId == 1).ToList();
var fptdocassets = fpt.CouttsPositionSection.AssetClassAssets.Select(e => e.StaticDataAssetClassAsset).ToList();
var listTemp = FPTStaticDataAssetClassAssetlist.Where(i => !fptdocassets.Contains(i)).ToList();
FPTAssetClassAsset a = new FPTAssetClassAsset();
a.StaticDataAssetClassAsset = listTemp[random.Next(0, listTemp.Count())];
a.Currency = a.StaticDataAssetClassAsset.Currency;
a.Description = a.StaticDataAssetClassAsset.Name + " Descr";
a.Holdings.Add(GenerateFPTRatedFinancialAssetHolding());
FillCommonRateFinancialAssetData(a, fpt);
fpt.UpdateXrates(a.StaticDataAssetClassAsset.CurrencyId);
return a;
}
When i run the method it will be called 4 times with 4 different parameters. If i set 4 optional parameters that's fine, however they all have different variable names. Below the variable name will go between the stars, but i have 4 so is there any way of having the variable change its value or name?
var fptdocassets = fpt.*variable of parameter passed*.AssetClassAssets
I solved this by passing in a string instead, and using the following method to return the object that it matched.
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}

How to treat function as string?

just I want to ask is it possible to Call function as ToUpper or ToLower() as string for example f.Name.Replace(" ", "_").ToLower()".ToLower()" or "ToUpper" for example if user select convert file name to ToLower() from dropdown list.it will take the value 'ToLower' and added to in of the function and executed the function call
Well, not cleanly. You could use reflection to find the method but you'd have to know the exact type that the function will be applied to since you won't get sophisticated binding like you do at compile-time. Plus you'll be limited to one method signature (in this case, no input parameters and returns a string).
To support any string function with that signature you could use:
string val = f.Name.Replace(" ", "_").ToLower();
string strCommand = "ToUpper";
MethodInfo theMethod = typeof(string).GetMethod(strCommand,new Type[] {});
string result = (string)(theMethod.Invoke(val,null));
But a simple switch seems cleaner and safer here.
The conditional operator (?:) would probably be a better option here
var fileName = f.Name.Replace(" ", "_");
fileName = ddl.SelectedValue == "ToLower" ? fileName.ToLower() : fileName.ToUpper();
Using Reflection for something as trivial as this is pretty unnecessary.
If you know the methods you want to call before, you can register them in a dictionary (key = name of the function or something user friendly, value = function that performs the conversion):
var dict = new Dictionary<string, Func<string, string>>();
dict.Add("Lowercase", x => x.ToLower());
dict.Add("Uppercase", x => x.ToUpper());
You can bind the drop down list to the dictionary (text = Key, value = Value) and perform the conversion as follows (ddl is the name of the DropDownList):
var f = (Func<string, string>)ddl.SelectedValue;
var convStr = f(inputStr);
You can create a defined dictionary of functions, which you can access by name of the action. You will get rid of any conditional statements and of all reflection. Example is given below:
var actions = new Dictionary<string, Func<string, string>>()
{
//keys may have other, human-readable values
{"ToLower", s => s.ToLower()},
{"ToUpper", s => s.ToUpper()}
};
//you will receive this from drop down list, it's the name of the action
var userSelectedOption = "ToUpper";
//string that you want to process
var myString = "some other user input";
//selecting appropriate action and passing myString to it
var transformedString = actions[userSelectedOption](myString);
//prints "SOME OTHER USER INPUT"
Console.WriteLine(transformedString);
Using reflection, you can call a methods using a string:
String ToLower = "ToLower";
String SometString = "This Is My String";
Type stringType = typeof(String);
// Get the overload of ToLower that takes no parameters
MethodInfo method = stringType.GetMethod(ToLower, System.Type.EmptyTypes);
// Invoke the method with no parameters
String newString = (String)method.Invoke(SometString, null);
MessageBox.Show(newString);
If I have understood your question correctly, you want to call a method based on a string.
You can use reflection, which is a topic in and of itself, but to get you started you can do something like:
MethodInfo chosenMethod = typeof(string).GetMethod(methodName, Types.EmptyTypes);
chosenMethod.Invoke(stringToModify, new object[]{});
But if it is a very limited set of functions you want to expose, you should just do a switch statement over the user input:
switch(methodName)
{
case "ToLower":
stringToModify.ToLower();
break;
...
You can use a simple switch statement:
switch (value) // Assuming value is of type SomeEnum
{
case SomeEnum.ToLower:
return f.ToLower()
case SomeEnum.ToUpper:
return f.ToUpper();
default:
//Do the Default
break;
}
This is how you parse what you get from the UI:
public static T ParseEnum<T>( string value )
{
return (T) Enum.Parse( typeof( T ), value, true );
}
Perhaps you might need to avoid limitations is sort of a Runtime intepreter of C#, like eval() function in JavaScript, which is not easily nor trivial to implement, but there is a good library out there called C# Eval ( http://csharp-eval.com/Download.php ) that uses Reflection internally of course. It is heavier but more effective for this, or even for much more complex escenarios.
You might use it in this way for example:
class Person
{
public string Name;
public string Process(string expression)
{
return CsEval.Eval(this, expression);
}
}
And then might call it:
var f = new Person();
f.Name = "John";
f.Name = f.Process("Name.Replace(" ", "_").ToLower()");
Of course this is just an example of how it evaluate what is in the string, as you can see you just need to pass a "context" where the expression is going to mean something, which in this case is the current class ("this").

Searching for pages with any value in property

EPiServer only:
How do I search for pages with any value in a given property? I can do a search for pages with a specific value in the property, but I can't figure out how to search for "not empty".
For example, this doesn't work:
var criterias = newPropertyCriteriaCollection
{
new PropertyCriteria()
{
Condition = CompareCondition.NotEqual,
Name = "MyProperty",
IsNull = false,
Type = PropertyDataType.String,
Value = ""
}
};
var pages = DataFactory.Instance.FindPagesWithCriteria(PageReference.StartPage, criterias);
An exception is thrown, "The crieria value cannot be null or empty. Set the IsNull property to search for null."
Any ideas?
Yeah, this is confusing. In case anyone else stumbles on this, here's how to search for pages with a certain PageReference property set to something:
new PropertyCriteria()
{
createdCriteria.Name = "MyProperty";
createdCriteria.Type = PropertyDataType.PageReference;
createdCriteria.Condition = EPiServer.Filters.CompareCondition.NotEqual;
createdCriteria.Value = "0";
createdCriteria.IsNull = false;
}
Unless I'm missing a trick, this doesn't appear to be possible using the EPiServer PropertyCriteriaCollection.
I've had a dig around in reflector and here are my findings. The FPWC method eventually calls EPiServer.DataAccess.PropertySearchDB.FastFindPagesWithCriteria().
Within this method is the following:
foreach (PropertyCriteria criteria in criterias)
{
if (criteria.IsNull)
{
criteria.Value = null;
}
else if (string.IsNullOrEmpty(criteria.Value))
{
throw new EPiServerException("The crieria value cannot be null or empty. Set the IsNull property to search for null.");
}
...
}
So its not possible to search for an empty string value, without setting IsNull to true. This is then fed down to the EPiServer.DataAccess.PropertySearchDB.ExecuteCriteria method, which constructs and formats the DB command. Because IsNull is true, the netPropertySearchNull stored proc is used. Searching for a string needs to use the netPropertySearchString stored proc.
if (criteria.IsNull && !PageDB.IsMetaData(criteria.Name))
{
cmd.CommandText = "netPropertySearchNull";
}
My suggestion would be to load the full list of pages and filter using linq. Alternatively you could look into bypassing the API and implementing a direct DB query, or use some of the low level EPiServer data access methods (not recommended)
Apologies for my first answer - I really should test code before posting :)
I've seen something where the page has a a hidden bool property "Property X contains a value" that is set in the Saving event.
Then that bool property is used as a PropertyCriteria instead of the one you are REALLY interested in.
To find empty values you need to specify the IsNull property on the PropertyCriteria and use the Equal compare condition.
E.g
var criterias = newPropertyCriteriaCollection
{
new PropertyCriteria()
{
Condition = CompareCondition.NotEqual,
Name = "MyProperty",
IsNull = true,
Type = PropertyDataType.String
}
};

Categories

Resources