Using A Mapping's Properties In A Switch Statement - c#

I am trying to create some sort of mapping and construct a switch statement based on this.
The first thing I tried was this:
public class Class1
{
public void Test()
{
string testString_A = "A";
string testString_B = null;
switch (testString)
{
case Options.O1.aName:
testString_B = Options.O1.bName;
break;
case Options.O2.aName:
testString_B = Options.O2.bName;
break;
}
}
}
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
public class Option
{
public string aName;
public string bName;
}
In this scenario, compiler complains that a constant value is expected for the switch cases.
So next, I tried the following but it does not work either. The .aName I try to use in the switch statement seems not accessible.
public Class1()
{
public void Test()
{
string testString = "A1";
switch (testString)
{
case Options.O1.aName:
...
}
}
}
public static class Options
{
public static Option_O1 O1 = new Option_O1();
public static Option_O2 O2 = new Option_O2();
}
public class Option_O1
{
public const string aName = "A1";
public const string bName = "B1";
}
public class Option_O2
{
public const string aName = "A2";
public const string bName = "B2";
}
How can I accomplish what I want?

There's a big difference between a string property / field variable (even if it is static or readonly), and a const string. The switch statement requires either literals, or const values in the case statements.
This explains why your first attempt didn't succeed (Error : "A Constant value is required").
In the second case, although you could obviously do this:
switch (testString)
{
case Option_O1.aName:
return Option_O1.bName;
case Option_O2.aName:
return Option_O2.bName;
}
but as soon as you try and 'cheat' the constant switch requirement by introducing the static class container, you're back to the same problem, although a more cryptic compiler error:
case Options.O1.aName: // Cannot be accessed by an instance reference
return Option_O1.bName;
Alternative to switch
I'm guessing here, but it seems that you need to build a run time mapping function.
Assuming that you always want to return the same data type (a string), I would suggest using a Dictionary keyed by the string you are trying to 'switch' on - this mapping can be built up at run time.
Here's an example of a statically bootstrapped map:
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
private static IDictionary<string, Option> myOptionMap = new []
{
Options.O1, Options.O2
}
.ToDictionary(x => x.aName);
Which you can use like so:
public string Test(string someAName)
{
if (myOptionMap.TryGetValue(someAName, out var myOption))
{
return myOption.bName;
}
// Oops not found
return string.Empty;
}
Unless there's more to this than your MVP, it's unlikely that you'll want to subclass your options per instance - Option_O1

Related

Is it possible to easily get variable names in a method as well as their values

Following my Is it possible to have a Function that takes any number of variables of any type?
I have the function that gets any number of any type of variables and it works perfectly
public string funcVars(params object[] paths)
{
string strVars = String.Join(", ", paths.Select(x => x.ToString()));
return strVars;
}
To call it I'd simply need to
string someString ="asd"; int someInt = 123; bool someBool=false;
funcVars(someString,someInt,someBool);
And the output would be
asd,123,false
is there any simple way I can also get the variable names as well as their values, so the output would be
asd,123,false,someString,someInt,someBool //(or any other similar form)
Or do I need to hardcode the names every time I call my method ?
funcVars("someString","someInt","someBool",someString,someInt,someBool);
What you really should be doing is creating a class to hold your variables:
internal class MyValues
{
internal string SomeString { get; set; }
internal int SomeInt { get; set; }
internal bool SomeBool { get; set; }
}
Then you can pass an instance of your class:
var mv = new MyValues() { SomeString = "asd", SomeInt = 123, SomeBool = false };
funcVars(mv);
Here is funcVars:
public string funcVars(MyValues values)
{
string strVars =
String.Join(", ", new[] { values.SomeString,
values.SomeInt.ToString(), values.SomeBool.ToString() });
return strVars;
}
Straight up stealing roy.ap's code and adding the "nameof()" method since getting the name of the property seemed to be apart of the question.
class Program
{
internal class MyValues
{
internal string SomeString { get; set; }
internal int SomeInt { get; set; }
internal bool SomeBool { get; set; }
}
static void Main(string[] args)
{
var mv = new MyValues() { SomeString = "asd", SomeInt = 123, SomeBool = false };
Console.WriteLine(funcVars(mv));
Console.ReadLine();
}
public static string funcVars(MyValues values)
{
string strVars =
String.Join(", ", new[]
{
nameof(values.SomeString), values.SomeString,
nameof(values.SomeInt), values.SomeInt.ToString(),
nameof(values.SomeBool), values.SomeBool.ToString()
});
return strVars;
}
}
There really isn't a way to get the variable names via the the function itself because the scope changes once you're in the method. That is even if you pass an array of objects, if you perform a foreach to go through each object you will give the individual objects a new scope specific name.
No, because the variables are not actually passed
No it is not possible, because the variables themselves are not actually passed. Their values are passed.
Consider this code:
string someString ="asd"; int someInt = 123; bool someBool=false;
funcVars(someString,someInt,someBool);
In your call to funcVars, all the parameters are passed by value. All three variables are copied, and copy of them is put on the stack. These stack variables are identified by completely different symbols-- (e.g. paths[0],paths[1], etc.)
After all, what would happen if you called it like this?
funcVars("Hello",245+25,test != null);
Obviously those values do not have variable names. There is no way your function can possibly retrieve what doesn't exist.
Use ExpandoObject instead
The System.Dynamic.ExpandoObject seems like a really good fit for this problem.
var args = new System.Dynamic.ExpandoObject();
args.SomeString = "hello";
args.SomeInt = 32;
args.SomeBool = false;
funcVars(args);
public static string funcVars(ExpandoObject inputs)
{
var sb = new StringBuilder();
foreach (KeyValuePair<string, object> kvp in inputs)
{
sb.Append(String.Format("{0} = {1}", kvp.Key, kvp.Value);
}
return sb.ToString();
}

Create a method which return a list of parameters (const string) from a class

I'm developing a class which contains some const strings
public static class Constants
{
public const string CarID= "car_id";
//public const string NumberID= "number_id"; // this is the second const string might be added, so
//the new created function can return the two
}
public class CarENParameters
{
public string Params { get; set; }
public CarENParameters(string carId)
{
Params = carId;
}
}
public static class CarPropertyProcess
{
//test params
public static CarENProps Parse(Uri uri,string content)
{
string carID= Regex.Matches(content, #"\$\('#CarXL'\)\.val\((\d+)\)", RegexOptions.None)[0].Groups[1].Value;
var parameters = new Dictionary<string, string>
{
{Constants.CarID, carID},
};
return new CarENProps(uri.AbsoluteUri, parameters);
}
public static CarENParameters GetParameters()
{
return new CarENParameters(Constants.CarID);
}
}
In the class Constants, I have one carID, now the case is it might have more than one const string like : public const string NumberID= "number_id";
So I want to create one function to return a list of those const strings, which are car_id and number_id with a class name CarENParameters but I havent figured out how to return a list by a get/set in a class, should I use dictionary or keyvaluespair to achieve that ? I'm quite new to C# so hope that I can have a better point of view from the helps of you guys. Thanks
Are you looking for something like this:
public static List<CarENParameters> GetParameters()
{
return new List<CarENParameters>()
{
new CarENParameters(Constants.CarID1),
new CarENParameters(Constants.CarID2),
new CarENParameters(Constants.CarID3)
}
}
You can use reflection for this
don't forget to put using System.Reflection;
// get class type
Type type = typeof(Constants);
// get a list of fields
FieldInfo[] fields = type.GetFields();
List<CarENParameters> list = new List<CarENParameters>();
// loop on field list
foreach (FieldInfo field in fields)
{
// if field is a string add it to our return list
if (field.FieldType == typeof(String))
list.Add(new CarENParameters((String) field.GetValue(null)));
}

Advice - How to implement the same code with different parameters

I would like an advice. My project have a lot of equals methods with different values, and i would like to do a single method that does the same.
The methods are this:
private void Enum1()
{
Console.WriteLine(Enum.GetValue(ENUM1.Code));
Console.WriteLine(Enum.GetValue(ENUM1.Info));
}
private void Enum2()
{
Console.WriteLine(Enum.GetValue(ENUM2.Code));
Console.WriteLine(Enum.GetValue(ENUM2.Info));
}
private void Enum3()
{
Console.WriteLine(Enum.GetValue(ENUM3.Code));
Console.WriteLine(Enum.GetValue(ENUM3.Info));
}
This is the enums:
public enum ENUM1
{
Code = 1,
Info = 3
}
public enum ENUM2
{
Code = 91,
Info = 4
}
public enum ENUM3
{
Code = 6,
Info = 27
}
There is only a way to create a method by inserting the input type of enum to use? maybe a similar solution of this:
private void General("ENUM1")
{
var type = ENUM1;
switch (p)
{
case "ENUM1":
type = ENUM1;
case "ENUM2":
type = ENUM2;
case "CASALINGHI":
type = ENUM3;
default:
type = ENUM1;
}
Console.WriteLine(Enum.GetValue(type.Code));
Console.WriteLine(Enum.GetValue(type.Info));
}
I think something like this is what you are looking for:
private void General<T>()
{
var values = Enum.GetValues(typeof(T));
foreach(var value in values)
Console.WriteLine(value);
}
General<Enum1>();
General<Enum2>();
General<Enum3>();
Or this, depending on how you want to use it:
private void General(Type enumType)
{
var values = Enum.GetValues(enumType);
foreach(var value in values)
Console.WriteLine(value);
}
General(typeof(Enum1));
General(typeof(Enum2));
General(typeof(Enum3));
Why do you keep using enums, when you can easily use classes? Read more about Object-Oriented programming.
Create a single class:
public class MyEnum
{
public int Code
{
get; set;
}
public int Info
{
get; set;
}
public string Display()
{
Console.WriteLine(this.Code);
Console.WriteLine(this.Info)
}
//
// This will keep your enums static, available from any method
//
private static List<MyEnum> _globals = new List<MyEnum();
public static List<MyEnum> Globals ()
{
if (this._globals.Count == 0)
{
this._globals.Add(new MyEnum(){ Code = 1, Info = 3 });
this._globals.Add(new MyEnum(){ Code = 91, Info = 4 });
this._globals.Add(new MyEnum(){ Code = 6, Info = 27 });
}
return this._globals;
}
}
After this you can easily print out all the enums with the following code:
foreach (MyEnum* en in MyEnum.Globals())
{
en.Display();
}
Please look into solutions similar to this one, since your enum's obviously represent some data.

C# Object Reference : How can i do it?

This is class Test
public class Test
{
public string mystr;
}
And i call it from method :
string my = "ABC";
Test test = new Test();
test.mystr = my;
test.mystr = "";
Result of a bit code above are : my = "ABC" and test.mystr = ""
How can I set my to empty string "" when I change test.mystr = ""?
If I understand correctly, you want the variables my and test.myStr to be linked, so if one changes, the other changes?
The answer is simple: It cannot!
A string is an immutable class. Multiple references can point to a string instance, but once this instance is modified, a string instance is created with the new value. So a new reference is assigned to a variable, while the other variables still point to the other instances.
There is a workarounds, but I suspect you will not be happy with it:
public class Test
{
public string mystr;
}
Test myTest1 = new Test { myStr = "Hello" };
Test myTest2 = myTest1;
Now, if you change myTest1.myStr, the variable myTest2.myStr will also be modified, but that is simply because the myTest1 and myTest2 are the same instances.
There are other solutions like these, but the all come down to the same aspect: A class holding a reference to a string.
Strings in .NET are immutable and don't work like that. One approach you could try is to use a mutable wrapper for the strings.
public class StringReference
{
public string Value {get; set;}
public StringReference(string value)
{
Value = value;
}
}
public class Test
{
internal StringReference mystr;
}
StringReference my = new StringReference("ABC");
Test test = new Test();
test.mystr = my;
test.mystr.Value = "";
// my.Value is now "" as well
string my = "ABC";
Test test = new Test();
Note here, that there is no relationship between your Test class and the string my. I am not entirely sure what you are trying to achieve, but we could do it like this:
public class Test
{
private string _mystr;
private Action<string> _action;
public Test(Action<string> action)
{
_action = action;
}
// Let's make mystr a property
public string mystr
{
get { return _mystr; }
set
{
_mystr = value;
_action(_mystr);
}
}
}
Now you can do this:
string my = "ABC";
Test test = new Test((mystr) => { if(string.IsNullOrEmpty(mystr)) my = ""; });
test.mystr = my;
test.mystr = "";

Using DefaultIfEmpty with an object?

I saw an example on MSDN where it would let you specify the default value if nothing is returned. See below:
List<int> months = new List<int> { };
int firstMonth2 = months.DefaultIfEmpty(1).First();
Is it possible to use this functionality with an object? Example:
class object
{
int id;
string name;
}
code:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(/*something to define object in here*/).name;
UPDATE:
I was thinking I could do something like this:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(new myObjec(-1,"test")).name;
But haven't been able to. It should be noted that I am actually trying to use this method on an object defined in my DBML using LINQ-To-SQL. Not sure if that makes a difference in this case or not.
You need to pass an instantiated class as a parameter of the DefaultIfEmpty.
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test() { i = 1, name = "testing" }).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
}
To add to it and make it a bit more elegant (IMO) add a default constructor:
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test()).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
public Test() { i = 2; name = "testing2"; }
}
As per the MSDN page on this Extension Method you can do what you want:
http://msdn.microsoft.com/en-us/library/bb355419.aspx
Check the sample on this page for an example on how to use this with an object.
i must admit i am not too sure i understand your question, but i'll try to suggest using double question mark if the returned object might be null. Like so:
myList.FirstOrDefault() ?? new myObject();
You can create a default Object Like this:
Object o_Obj_Default = new Object();
o_Obj_Default.id = 3;
o_Obj_Default.name = "C";
And add it to your default value :
string defaultName = objs.DefaultIfEmpty(o_Obj_Default).First().name;
If your list "objs" is empty, the result will be "C"

Categories

Resources