C# alternative to runtime optional parameters? [duplicate] - c#

This question already has answers here:
Default parameter for value must be a compile time constant?
(7 answers)
Closed 5 months ago.
I'm not sure how to go about doing this, after a bit of research I couldn't really find something that fits my needs. The only thing I could find is from another coding language entirely. I think I might be over-complicating things but I'm blanking and can't seem to wrap my head around this problem.
Here's a simplified example of what I'm trying to achieve, say I have a class Item:
public class Item {
public int val { get; set; } = 1;
public void Link(Item i) { ... }
}
And in some other class that manages Items, I have this method:
void LinkPair(int val = GetLowestVal()) {
var pair = GetItems(val);
pair[0].Link(pair[1]);
}
Basically what I want it to do is: if given a value val, find and link a pair of Items with matching values, otherwise just link a pair both with the lowest value in the list. Unfortunately void LinkPair(int val = GetLowestTier()) isn't a valid signature. Also, since val is an int I can't set its default to null, otherwise I would so something like this I presume:
void LinkPair(int val = null) {
val = val ?? GetLowestVal();
...
I'd like to avoid having to create another overloaded method since I might end up with quite a few variations of these. Any help would be appreciated!

You can't assign null to an int. You'll have to use int?
void LinkPair(int? val = null) {
val = val ?? GetLowestVal();
If you know that val will never be 0 you can use this as the default :
void LinkPair(int val = 0) {
val = val!=0? val : GetLowestVal();
0 is the default for numbers so this is equivalent to :
void LinkPair(int val = default) {
val = val!=0 ? val : GetLowestVal();

Related

Is there a way to create a Pass-By-Reference list of managed-type variables?

edit; Based on responses, I may have been unclear in my final goal. I've updated the last section.
Situation
I have a number of variables which I need to perform the same operation on. In this case, they are strings, and can at the point we reach this code have the value null, "", "Blank", or they could already have an assigned other value that I want to keep.
if (String.IsNullOrEmpty(MyVar1) || "Blank".Equals(MyVar1))
MyVar1 = null;
if(String.IsNullOrEmpty(MyVar2) || "Blank".Equals(MyVar2))
MyVar2 = null;
...
if(String.IsNullOrEmpty(MyVar10) || "Blank".Equals(MyVar10))
MyVar10 = null;
Being a programmer that wants to keep my code clean and this block drives me mad, I'm looking for a way to create a list of these variables, and perform this same if statement + null assignment on each.
For an example, here's what I'd like to do:
MyVar1 = "Blank";
DreamDataStructure varList = new DreamDataStructure() { MyVar1, MyVar2, ..., MyVar10 };
foreach(ref string MyVar in varList)
{
if(String.IsNullOrEmpty(MyVar) || "Blank".Equals(MyVar))
MyVar = null;
}
Console.WriteLine(MyVar1); //Should now be null
What Doesn't Work
1) Because my variables are strings, I can't do something like this.
var myListOfVariables = new[] { &MyVar1, &MyVar2, ..., &MyVar10 };
If I could, I'd be able to foreach over them as expected. Because string is a managed type though, it cannot be passed by reference like this.
2) Similarly, if I just made a List<string> of the variables, they would be passed by value and wouldn't help my case.
3) These variables can't be wrapped in an outer object type, as they need to be used as strings in a large number of places in a legacy application. Assume that it would be too large an effort to change how they're used in every location.
Question
Is there a way to iterate over string (or other managed type) variables in a pass-by-reference way that will allow me to put the entire operation inside of a loop and reduce the duplication of code that's happening here?
The goal here is that I can use the original variables later on in my code with the updated values. MyVar1, etc, are referenced later on already by legacy code which expects them to be null or have an actual value.
If I understand your question correctly, I don't think what you want to do is possible. Please see this question: Interesting "params of ref" feature, any workarounds?
The only thing I can suggest (which I know doesn't answer your question) is creating a method to avoid duplication of your conditional logic:
void Convert(ref string text)
{
if (string.IsNullOrEmpty(text) || "Blank".Equals(text))
{
text = null;
}
}
You could create a function instead of passing references, which would also be more readable.
string Validate(string inputString)
{
return string.IsNullOrEmpty(inputString) || "Blank".Equals(inputString) ? null : inputString;
}
<...>
MyVar1 = Validate(MyVar1);
Update:
Now I get what you're trying to do. You have a bunch of variables, and you want to perform some sort of bulk operation on them without changing anything else. Putting them in a class isn't an option.
In that case you're really stuck operating on them one at a time. There are ways to shorten it, but you're pretty much stuck with the repetition.
I'd
create a string SanitizeString(string input) function
type x = SanitizeString(x); once for each variable
copy and paste the variable names to replace x.
It's lame, but that's about all there is.
Perhaps this would be a better approach. It ensures that the values are always sanitized. Otherwise you can't easily tell whether the values have been sanitized or not:
public class MyValues
{
private string _value1;
private string _value2;
private string _value3;
public string Value1
{
get { return _value1; }
set { _value1 = Sanitize(value); }
}
// repeat for other values
private string Sanitize(string input) =>
string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
}
That's one option. Another is to sanitize the inputs earlier. But ideally we want to ensure that a given class is always in a valid state. We wouldn't want to have an instance of a class whether the values may or may not be valid. It's better to ensure that they are always valid.
ref doesn't really factor into it. We don't need to use it often, if ever. With a value type or string we can just return a new value from a function.
If we're passing a reference type and we want to make changes to it (like setting its properties, adding items to a list) then we're already passing a reference and we don't need to specify ref.
I'd try to write methods first without using ref and only use it if you need to. You probably never will because you'll succeed at whatever you're trying to do without using ref.
Your comment mentioned that this is a legacy app and it's preferable not to modify the existing class. That leaves one more option - reflection. Not my favorite, but when you say "legacy app" I feel your pain. In that case you could do this:
public static class StringSanitizer
{
private static Dictionary<Type, IEnumerable<PropertyInfo>> _stringProperties = new Dictionary<Type, IEnumerable<PropertyInfo>>();
public static void SanitizeStringProperties<T>(T input) where T : class
{
if (!_stringProperties.ContainsKey(typeof(T)))
{
_stringProperties.Add(typeof(T), GetStringProperties(typeof(T)));
}
foreach (var property in _stringProperties[typeof(T)])
{
property.SetValue(input, Sanitize((string)property.GetValue(input)));
}
}
private static string Sanitize(string input)
{
return string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
}
private static IEnumerable<PropertyInfo> GetStringProperties(Type type)
{
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(property => property.PropertyType == typeof(string) && property.CanRead && property.CanWrite);
}
}
This will take an object, find its string properties, and sanitize them. It will store the string properties in a dictionary by type so that once it has discovered the string properties for a given type it won't have to do it again.
StringSanitizer.SanitizeStringProperties(someObject);
you can simply use a string[] and get the changes back to the caller method like this.
public Main()
{
var myVar1 = "Blank";
var myVar2 = "";
string myVar3 = null;
var myVar4 = "";
string[] dreamDataStructure = new string[] { myVar1, myVar2, myVar3, myVar4 };
}
private void ProcessStrings(string[] list)
{
for(int i = 0; i < list.Length; i++)
{
if (String.IsNullOrEmpty(list[i]) || "Blank".Equals(list[i]))
list[i] = null;
}
}

Need approach for Setting value to a property based on numerous conditions [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have many properties spread across a number of classes. Values to these properties need to be assigned based on a number of conditions (around 5 to 8 for each property). I am looking for an alternative for numerous 'if else' conditions.
I have come across 'Rule Engine' off late but AFAIK it can be used for validating the rules.
Any design suggestion would be of great help.
I'm not sure whether this is a "better" solution for you, but I'll try to explain.
Value to these properties need to be assigned based on a number of conditions (around 5 to 8 for each property).
I think you mean that you always need to write this, which is annoying:
if (condition1 && condition2 && condition3 && condition4 && condition5) {
Property1 = Value1;
}
if (condition1 && condition2 && condition3 && condition4 && condition5) {
Property2 = Value2;
}
// ...
I think maybe this method can solve your problem?
public static void SetValueForPropertyIf<T>(Predicate<object>[] conditions, ref T property, T value) {
foreach (var predicate in conditions) {
if (!predicate(null)) {
return;
}
}
property = value;
}
And you can just call the method with a list of lambda expressions, ignore the argument (because it's always null), a variable to be passed by reference, and a value to set if all the conditions are met.
However, this only works for variables because I'm pretty sure properties cannot be passed by reference (with the ref keyword). So you have to declare your properties like this:
private int someVariable;
public int SomeVariable {
get {return someVariable;}
set {someVariable = value;}
}
And if you don't like the parameter of the Predicate delegate not being used, define your own delegate!
public delegate bool MyDelegate();
Here is an example of how to use this method, in case you didn't understand what I meant.
class MyClass {
private int someVariable;
public int SomeVariable {
get {return someVariable;}
set {someVariable = value;}
}
public MyClass() {
someVariable = 10;
MyDelegate[] conditions = {
(() => 7 < 10),
(() => 77 == 77),
(() => "Sweeper is awesome".Contains("Sweeper")),
(() => String.IsNullOrEmpty(""))
};
SetValueForPropertyIf(conditions, ref someVariable, 20);
}
}
In this class's constructor, I first created some conditions, which are all true. Then I call the method with these conditions. Note that I used someVariable (The field) instead of SomeVariable (The property) as the ref parameter.
And then you can print SomeVariable:
MyClass mc = new MyClass();
Console.WriteLine(mc.SomeVariable);
The output is 20. Hooray!

Check if value is in Enum range without using IsDefined

There are a few other Questions on how to convert Enums and what happens if the value parsed is out-of-range, like in:
public enum SomeTypes
{
SomeType1 = 1,
SomeType2 = 2,
SomeType3 = 3
}
public class SomeClass
{
...
var inRange = (SomeTypes) 1;
var outOfRange = (SomeTypes) 5;
...
}
Going out-of-range will not produce any error.
But I found the hard way that if you try to serialize-deserialize an enum with an out-of-range value you'll get weird errors. For example, I was getting something like
"error parsing the message or timeout exceeded"
which kept me looking for other reasons than the enum out-of-range.
Suggestions to handle this are by the means of the Enum.IsDefined. That seems to work quite nicely, but then there's this rather bold warning on msdn:
"Do not use System.Enum.IsDefined(System.Type,System.Object) for enumeration range checks as it is based on the runtime type of the enumeration, which can change from version to version."
So, my question is, can we safely use Enum.IsDefined or what is the correct way to check if the value of an enum is out-of-range without using the Enum.IsDefined?
Use Enum.GetValues():
public bool IsInRange(int value){
var values = Enum.GetValues(typeof(SomeTypes)).Cast<int>().OrderBy(x => x);
return value >= values.First() && value <= values.Last();
}
[EDIT]
In case you want to check if the item is defined instead of just checking if it's inside the range, you can do similarly:
public bool IsDefined(int value){
var values = Enum.GetValues(typeof(SomeTypes)).Cast<int>().OrderBy(x => x);
return values.Contains(value);
}
There is an option for something simpler:
int value;
bool isInRange = string.IsNullOrEmpty(Enum.GetName(typeof(myEnumType), value));
I did a similar thing with objects DataContract
You must decorate the items in the list with [EnumMember] and then you could obtain the enum name with this method. So you would know if value exists in the enum cos returns his enum name.
public static string GetEnumNameFromValue(System.Type typeEnum, string value)
{
FieldInfo[] fis = typeEnum.GetFields();
foreach (FieldInfo fi in fis)
{
EnumMemberAttribute[] attributes = (EnumMemberAttribute[])fi.GetCustomAttributes(typeof(EnumMemberAttribute), false);
if (attributes.Length > 0)
{
if (string.Compare(attributes[0].Value, value, true) == 0)
{
return fi.Name;
}
}
}
return null;
}

Why does assignment operator return the assigned value in C#? [duplicate]

This question already has answers here:
Why do assignment statements return a value?
(14 answers)
Closed 9 years ago.
The assignment operator in C# returns the assigned value.
It's not clear where/how this feature can be helpful. Using it in a weird syntax like this can save you a line of code, but won't do any good to readbility:
private String value;
public void SetAndPrintValue(String value)
PrintValue(this.value = value);
}
private static void PrintValue(String value) {
/* blah */
}
What is its purpose then?
Chained assignment is a staple of many languages going back to C (and probably earlier). C# supports it because it's a common feature of such languages and has some limited useā€”like the goto statement.
Occasionally you might see code like this:
int a, b, c;
for(a = b = c = 100; a <= b; c--)
{
// some weird for-loop here
}
Or this:
var node = leaf;
while(null != node = node.parent)
node.DoStuff();
This might make some code a little more compact, or allow you to do some clever tricks, but it certainly doesn't make it more readable. I'd recommend against it in most cases.
I generally use it for assigning the same properties to a control.
btnSubmit.Enabled = btnAdd.Enabled = btnCancel.Enabled = txtID.Enabled= false;

Check that integer type belongs to enum member

I want to check that some integer type belongs to (an) enumeration member.
For Example,
public enum Enum1
{
member1 = 4,
member2 = 5,
member3 = 9,
member4 = 0
}
Enum1 e1 = (Enum1)4 gives me member1
Enum1 e2 = (Enum1)10 gives me nothing and I want to check it.
Use Enum.IsDefined
Enum.IsDefined(typeof(Enum1), 4) == true
but
Enum.IsDefined(typeof(Enum1), 1) == false
As Sam says, you can use IsDefined. This is somewhat awkward though. You may want to look at my Unconstrained Melody library which would let you us:
Enum1 e2 = (Enum1)10;
if (e2.IsNamedValue()) // Will return false
{
}
It's probably not worth it for a single enum call, but if you're doing a lot of stuff with enums you may find some useful things in there.
It should be quicker than Enum.IsDefined btw. It only does a linear scan at the moment, but let me know if you need that to be improved :) (Most enums are small enough that they probably wouldn't benefit from a HashSet, but we could do a binary search...)
int testNum = 5;
bool isMember = Enum.GetValues(typeof(Enum1)).Cast<int>().Any(x => x == testNum);
You look through the values of the enum and compare them to the integer.
static bool EnumTest(int testVal, Enum e)
{
bool result = false;
foreach (var val in Enum.GetValues(typeof(Enum1)))
{
if ((int)val == testVal)
{
result = true;
break;
}
}
return result;
}
Edit: Looks like Sam has a better solution.
You can use Enum.GetValues to get all defined values. Then check if your value exists in that list.
http://msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
Be careful this won't work if you have an enum for 3 (Apples and Pears) the methods above won't detect it as valid.
[Flags]
public enum Fruit
{
Apples=1,
Pears=2,
Oranges =4,
}
Here's a succinct little snippet from an extension method I wrote a few years ago. Combines TryParse with IsDefined to do it all in one swoop and handle values that don't exist in the enum.
if (value != null)
{
TEnum result;
if (Enum.TryParse(value.ToString(), true, out result))
{
// since an out-of-range int can be cast to TEnum, double-check that result is valid
if (Enum.IsDefined(typeof(TEnum), result.ToString() ?? string.Empty))
{
return result;
}
}
}
Here's the extension for integer values
public static TEnum ParseToEnum<TEnum>(this int value, TEnum? defaultValue = null, bool useEnumDefault = false) where TEnum : struct
{
return ParseToEnumInternal(value, defaultValue, useEnumDefault);
}
And a usage
public enum Test
{
Value1 = 1,
Value2 = 3
}
var intValue = 1;
var enumParsed = intValue.ParseToEnum<Test>(); // converts to Test.Value1
intValue = 2;
enumParsed = intValue.ParseToEnum<Test>(); // either throws or converts to supplied default
enumParsed = 3.ParseToEnum<Test>(); // converts to Test.Value2
Some people don't like how it dangles off the end of the (potentially nullable) value, but I have an extension that handles null values of nullable types (int?) and I like it myself, so ...
I can post like a Gist of the whole extension method with all the overloads if you're interested.
Use:
if (Enum.IsDefined(typeof(Fruit),e2))
{
//Valid Value
}
else
{
//Invalid ENum Value
}
Found this useful. https://stackoverflow.com/a/64374930/16803533
no need to use IsDefined and No range checking

Categories