Pass enum as a parameter in C# or any alternatives - c#

public EnumA
{
name = 1,
surname = 2
}
public EnumB
{
name = 50,
surname = 60
}
public void myMethod(User u,Enum e)
{
//Enum e can be either EnumA or EnumB
//Do something with the Enum Passed
}
Let's say I have the above code but instead of specifiying the Enum in the method like I'm doing above, I'd like to select the enum which is passed through the method parameter. Is there any way of doing so?

You can do this via reflection, but I'm worried that you don't understand enumerations properly. It kind of looks to me like you are trying to use them as class instances to hold arbitrary data, in which case, you really should be using a real class.
In case I'm wrong, I've included code below to do what you are asking for, but I don't think it will be very useful for you.
void Main()
{
Test(EnumA.First);
Console.WriteLine("-----");
Test(EnumB.B);
}
void Test(Enum theEnum)
{
Type t = theEnum.GetType();
foreach (string element in Enum.GetNames(t))
{
Debug.WriteLine(element + " = " + (int) Enum.Parse(t, element));
}
}
enum EnumA
{
First = 1,
Second = 2
}
enum EnumB
{
A = 1,
B = 2,
C = 3
}
It generates the following output:
First = 1
Second = 2
-----
A = 1
B = 2
C = 3
I think this is more what you are trying to do though:
void Main()
{
Person A = new Person()
{
Name = "John",
Surname = "Doe"
};
Person B = new Person()
{
Name = "Jane",
Surname = "Doe"
};
A.ShowInfo();
Console.WriteLine("----");
B.ShowInfo();
}
class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public void ShowInfo()
{
Debug.WriteLine("Name=" + Name);
Debug.WriteLine("Surname=" + Surname);
}
}
It output the following:
Name=John
Surname=Doe
----
Name=Jane
Surname=Doe

Have you tried the following:
public void myMethod(User u,Enum e)
{
if (e is EnumA)
{
EnumA ea = (EnumA)e;
// Do something with ea
}
else if (e is EnumB)
{
EnumB eb = (EnumB)e;
...
}
}

you have use generic type for this operation.
below code is showing a sample code (as Console app);
class Program
{
static void Main(string[] args)
{
myMethod<EnumA>("deneme", EnumA.name);
}
public enum EnumA
{
name = 1,
surname = 2
}
public enum EnumB
{
name = 50,
surname = 60
}
public static void myMethod<T>(string u, T e)
where T : struct,IConvertible
{
if (typeof(T) == typeof(EnumA))
{
Console.WriteLine("EnumA");
}
else if (typeof(T) == typeof(EnumB))
{
Console.WriteLine("EnumB");
}
Console.ReadLine();
}
}

You could use overloading:
public void myMethod(User u, EnumA e)
{
// Call a function common to both
}
public void myMethod(User u, EnumB e)
{
// Call a function common to both
}
I guess C# 7.3 allows you to do something like:
public void myMethod(User u, TEnum e) where TEnum : Enum
{
//Enum e can be either EnumA or EnumB
//Do something with the Enum Passed
}
I used something like this for a pre-7.3 project and it was a little ugly, but WAY better and more readable than any other way I could find:
public void myMethod(User u, object e)
{
// Test to make sure object type is either EnumA or EnumB
// Call a function common to both
// object e can be either EnumA or EnumB by casting like ((EnumA)e) or ((EnumB)e)
}

This is not how enums behave (or should behave). You're basically creating two different instances of enums. This is why classes exist in C#. Consider creating a class:
public class SomeEnum
{
public int Name;
public int Surname;
private SomeEnum(int name, int surname)
{
Name = name;
Surname = surname;
}
public static SomeEnum EnumA => new SomeEnum(1, 2);
public static SomeEnum EnumB => new SomeEnum(50, 60);
}
And changing your method to this:
public void myMethod(User u, SomeEnum e)
{
// Enum e can be either EnumA or EnumB
// Do something with the Enum passed
}
I changed as least code as possible as I'm not sure what the purpose is of these 'Enums', but this way you'll be able to create as many instances as you want, without your code getting messy with all of these identical Enum specifications.
To use this method with EnumA for example you can call myMethod(user, SomeEnum.EnumA).
This way it's only possible to use the specified enums (EnumA and EnumB). Alternatively, if you want to create enums on-the-fly, the code can be changed to:
public class SomeEnum
{
public int Name;
public int Surname;
public SomeEnum(int name, int surname)
{
Name = name;
Surname = surname;
}
}
This way you can call the method with myMethod(user, new SomeEnum(1, 2)).

Related

Using A Mapping's Properties In A Switch Statement

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

Generic class where T : Class clarification

There are semi answer to this question which I have read through thoroughly, as well as all things MSDN about generic classes but I am still having trouble when a generic class inherits from another class: where T: ClassName
For example, here is my generic list class
public class MyGenericList2<T> where T : Person
{
private T[] list;
public MyGenericList2(int size)
{
list = new T[size];
}
public T getItem(int index)
{
T temp = default(T);
temp = list[index];
return temp;
}
public void setItem(int index, T value)
{
list[index] = value;
}
public void DisplayList()
{
for (int i = 0; i < list.Length; i++)
{
Console.Out.WriteLine(list[i]);
}
}
}
It inherits from the person class:
NOTE: It is shortened for clarity sake
public abstract class Person
{
protected string firstName;
// Getters
public string getFirstName()
{
return this.firstName;
}
public void setFirstName(string fname)
{
this.firstName = fname;
}
}
When I try to call it I get an error about trying to convert a string to a {namespace}.Person which I sort of get, in that I am trying to put a string into a 'Person' box, but how does one call the class using this mechanism?
Here is the main method
public static void Main(string[] args)
{
MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);
Student st1 = new Student();
st1.setFirstName("Thor");
studentGeneric.setItem(0, st1); //This does not work
studentGeneric.setItem(1, Person.setFirstName("Odin"); // Does not work
studentGeneric.setItem(2, st1.setFirstName("Slepnir"); // Does not work
studentGeneric.DisplayList();
Console.ReadLine();
}
If I cut out the Where T : Person and use GenericList2<string> it works fine, which makes sense since it is string to string.
Any help would be appreciated
quick clarification Student inherits from Person:
public class Student : Person
{
// Student 1
private string studentID01 = "001";
public string getStudentID01()
{
return this.studentID01;
}
}
First of all I would recommend using public properties for your classes, for example:
public abstract class Person
{
public string FirstName { get; set; }
}
public class Student : Person
{
public string StudentId { get; set; }
}
This means your list code would work like this:
Student st1 = new Student();
st1.FirstName = "Thor";
studentGeneric.setItem(0, st1);
And you can even use this syntax:
studentGeneric.setItem(1, new Student
{
FirstName = "Odin"
});
Additionally, the .Net Framework already provides a really nice set of generic collection classes you can use so you don't really need your MyGenericList2<T> class. For example, the most commonly used class is System.Collections.Generic.List:
var people = new System.Collections.Generic.List<Person>();
people.Add(new Student
{
FirstName = "Odin"
});
Or even using the collection initialiser syntax:
var people = new System.Collections.Generic.List<Person>
{
new Student
{
FirstName = "Odin"
}
});
Finally, the problem you are having with outputting your values to the console is because C# doesn't know what to do with your class so by default outputs the value of student.ToString(). And becaue you haven't told your class what to do with it, it just outputs the name of the type. You can either override ToString or, much simpler just call the getFirstName() method:
Console.WriteLine(list[i].getFirstName());
You are using setItem incorrectly. This method can be used to set the value of elements in the list array in an instance of MyGenericList2 class.
To use the setFirstName method on an instance of the Student class, first use getItem to return the object instance. For example:
public void Main(string[] args)
{
MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);
Student st1 = new Student();
st1.setFirstName("Thor");
studentGeneric.setItem(0, st1);
Student st2 = new Student();
studentGeneric.setItem(1, st2);
studentGeneric.getItem(1).setFirstName("Odin");
Student st3 = new Student();
studentGeneric.setItem(2, st3);
studentGeneric.getItem(2).setFirstName("Slepnir");
studentGeneric.DisplayList();
Console.ReadLine();
}
To display the list contents correctly, replace your DisplayList() method with:
public void DisplayList()
{
for (int i = 0; i < list.Length; i++)
{
if(list[i] != null){
Console.Out.WriteLine("{0}: {1}", i, list[i].getFirstName());
}
else
{
Console.Out.WriteLine("{0}: [NULL]", i);
}
}
}

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.

Classes convertor

I have the following class People:
class People
{
public enum Gender
{
Man = 'w',
Woman = 'f'
}
public struct Person
{
public string First, Last;
public Gender Gender;
public int Age;
public float Height, Weight;
}
public struct Group
{
public int Members;
public string Name;
}
}
Now, we are located in the class Program:
class Program
{
static void Main( string[] args )
{
People.Person p = new People.Person();
p.First = "Victor";
p.Last = "Barbu";
p.Age = 14;
p.Height = 175;
p.Weight = 62;
p.Gender = People.Gender.Man;
Console.ReadLine();
}
}
I want to put a line like this:
Console.Write( x.toString() );
How can I customize the x.toString() method, so the result to be the following in the Console
Victor Barbu
14 years
Man
175 cm
62 kg
?
Thanks in advance!
Just overrive the ToString() method
public override string ToString()
{
// return the value you want here.
}
You want to override the ToString method in the Person class. See: http://msdn.microsoft.com/en-us/library/ms173154(v=vs.80).aspx
In your case
public class Person
{
// Snip
public override string ToString()
{
return this.First + " " + this.Last;
}
}
If you then do
Console.WriteLine(person.ToString());
The expected output would be the first and last name, you can obviously extend this to include your other fields and line breaks, etc.
Side note; what you are doing is really "pretty printing" I would suggest creating a static method "public static string PrettyPrintPerson(Person p)" or similar, to deal with textual formatting of the class.
class People
{
public override string ToString()
{
//This will return exactly what you just put down with line breaks
// then just call person.ToString()
return string.format("{1} {2}{0}{3} years{0}{4}{0}{5} cm{0}{6} kg", Environment.NewLine,
First, Last, Age, Gender, Height, Weight);
}
}

C# shortcut notation to create class instance

I'm sure there was a way to easily create an instance of a class but my search of the great interwebs hasn't found it. Lets say I have this:
List<LicencedCustomer> leftList = new List<LicencedCustomer>();
leftList.Add(new LicencedCustomer (LMAA_CODE:"1",LICENSE_NUMBER:"1",TRADING_NAME:"Bobs Liquor",STATE:"NSW",POSTCODE:"2261"));
My class looks like the below.
public class LicencedCustomer
{
public string LMAA_CODE {get; set;}
public string LICENSE_NUMBER {get; set;}
public string TRADING_NAME {get; set;}
public string STATE {get; set;}
public string POSTCODE {get; set;}
public LicencedCustomer(string LMAA_CODE, string LICENSE_NUMBER, string TRADING_NAME, string STATE, string POSTCODE)
{
this.LMAA_CODE = LMAA_CODE;
this.LICENSE_NUMBER = LICENSE_NUMBER;
this.TRADING_NAME = TRADING_NAME;
this.STATE = STATE;
this.POSTCODE = POSTCODE;
}
...
Without the constructor immediately above, I get an error that the class doesn't contain a constructor that takes 5 arguments (initially I tried it with the values only and no field names in the List.Add function).
Is there a shortcut that allows assignment to properties on creation, without needing to define the constructor explicitly?
Thanks!
EDIT: Wide ranging curiosity has resulted from the capitalised properties - they are only that way because they've been built to reflect the headings of an import file. Not my preferred method!
When you use new ( ) you call a constructor that matches the parameters. If you have no defined constructors you will get an implicit parameter less constructor.
To use the shortcut initializer use something like this.
public class sCls
{
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI"};
}
Edit
From comments if you add a consturctor that takes a paramter you lose the implict paramterless constructor
public class sCls
{
public sCls(string setB)
{
B = setB;
}
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI"}; // ERROR error CS1729: 'csCA.Program.sCls' does not contain a constructor that takes 0 arguments
}
You can also use any constructor with the initializer list
public class sCls
{
public sCls(string setB)
{
B = setB;
}
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls("hi") {A = 4, B = "HI"};
}
Remember that in all cases the constructor is called before the initializer list even if it has a parameter less constructor. So base class constructions or anything else that happens in the construction of the object will happen first.
public class BSE
{
public BSE()
{
BaseA = "Bob";
}
public string BaseA;
}
public class sCls :BSE
{
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI" };
Console.WriteLine("{0}", oCls.BaseA);//Prints Bob
}
Add a default constructor, then try something like:
new LicencedCustomer() { LMAA_CODE = ..., LICENSE_NUMBER = ..., ... };
Side note: It's not conventional to capitalize properties.

Categories

Resources