How do I select a C# variable using a string - c#

I have a string user setting and want to select a particular variable with the same name during the startup of my C# Windows app.
e.g.
I have a user setting (string) called UserSelectedInt, which is currently set to 'MyTwo'. (Please note that my variables are actually a lot more complex types than integers, I've just used them as examples.)
public static int MyOne = 12345;
public static int MyTwo = 54321;
public static int MyThree = 33333;
public int myInt = SelectMyVariableUsing(MyApp.Settings.Default.UserSelectedInt)
The user may have selected 'MyTwo' last time they closed the app, so that is the variable I want to select during startup. I hope I'm making sense.
Please can some let me know how would I achieve this?
Thanks

Use a Dictionary<string, int>. That allows you to assign an integer value to a number of strings. If the string is user input, you need to check that it is valid before trying to retrieve the corresponding integer.

Sounds like you are trying to implement the provider pattern. You may find using this is a better mechanism for you to use, especially as you say it is more complex than using ints.
In your code you would reference the particular provider using your MyApp.Settings.Default.UserSelectedInt setting.
I would say architecturally this would be a better mechanism than some of the other suggested answers.

// enumerate your list of property names (perhaps from a file)
var settings = new List<string>();
settings.Add("MyOne");
settings.Add("MyTwo");
settings.Add("MyThree");
var settingMap = new Dictionary<string, int>();
int value = 0;
foreach (var name in settings)
{
try
{
// try to parse the setting as an integer
if (Int32.TryParse((string)Properties.Settings.Default[name], out value))
{
// add map property name to value if successful
settingMap.Add(name, value);
}
else
{
// alert if we were unable to parse the setting
Console.WriteLine(String.Format("The settings property \"{0}\" is not a valid type!", name));
}
}
catch (SettingsPropertyNotFoundException ex)
{
// alert if the setting name could not be found
Console.WriteLine(ex.Message);
}
}
However, if you get to the stage where your variable list is HUGE then I would maybe look at actually accessing the properties file directly via some form of XML parsing.

The simplest way is probably to just use GetField.
Using your example just change the last line to:
var selectedField = MyApp.Settings.Default.UserSelectedInt
public int myInt = (int) GetType().GetField(selectedField).GetValue(this);
If the field or class is static the syntax should be:
var selectedField = MyApp.Settings.Default.UserSelectedInt
public int myInt = (int)typeof(YourClass).GetField(selectedField).GetValue(null);
See http://msdn.microsoft.com/en-us/library/system.reflection.fieldinfo.getvalue.aspx for more details.

Should be possible with Reflection

You could also use a Hashtable.
However, from the looks of it all your really wanting to do is store the value the user last selected hence I would probably just save it in the UserSettings as a string and then on load I would just parse the value.

I hope I am reading this right, but essentially, I feel you want to remember the value user selected last time. Since the application will be shutdown in the meantime, you are going to have to store it somewhere. Maybe in a file.

Too me it sounds more like you should use an enumeration in stead of static variables, consider the following example:
public enum MyVars
{
MyOne = 12345, MyTwo = 54321, MyThree = 33333
}
static void Main(string[] args)
{
Console.WriteLine(String.Format("Name:{0}, Val={1}", MyVars.MyOne.ToString(), (int)MyVars.MyOne ));
Console.ReadKey();
}
, it will output "Name:MyOne, Val=12345", with enumerations you can easily pick out the name of the variable.

Related

C# DataTable to Object Conversion Issue

I've written a piece of code for converting a DataTable object(which is created from an uploaded excel) to a list of custom object(ExcelTemplateRow in my case). While this method works fine when the values are supplied as expected(in terms of data type of the corresponding column), the code breaks and throws the below error when I try to give a random value(and hence the data type changes):
Object of type 'System.String' cannot be converted to type 'System.Nullable`1[System.Double]'
Below is the method for converting DataTable object to list:
public static List<T> ConvertToList<T>(DataTable dt)
{
var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName.ToLower()).ToList();
var trimmedColumnNames = new List<string>();
foreach (var columnName in columnNames)
{
trimmedColumnNames.Add(columnName.Trim().ToLower());
}
var properties = typeof(T).GetProperties();
return dt.AsEnumerable().Select(row => {
var objT = Activator.CreateInstance<T>();
foreach (var property in properties)
{
if (trimmedColumnNames.Contains(property.Name.Trim().ToLower()))
{
try
{
if(row[property.Name] != DBNull.Value)
{
property.SetValue(objT, row[property.Name]);
}
else
{
property.SetValue(objT, null);
}
}
catch (Exception ex)
{
throw ex;
}
}
}
return objT;
}).ToList();
}
My custom object looks somewhat like this:
public class ExcelTemplateRow
{
public string? Country {get; set;}
public double? Year {get; set;}
//....
//....
}
In the excel that I'm uploading, for the Year field, the code works fine when I give proper double values viz 2020, 2021, 2022 etc. but the code breaks when I give something wrong e.g 2023g. It then assumes I'm passing a string and hence the error. I tried by changing the declaration of the Year property to public object? Year {get; set;} but it doesn't help. I want to make the method robust enough to handle such scenarios. Any help and I'd be highly grateful.
There's a few things to consider here, but I'll try to be as terse as possible. When you say:
but the code breaks when I give something wrong e.g 2023g
This means the C# type system is working exactly as intended. A double should never be able to accept the value of "2023g". You probably want to store the year as a string instead. This may involve an intermediate stage of validation, where you import all of your data as a string (ExcelTemplateRow should all be strings in this case).
Then your work is ahead of you to validate the data, and then once you've handled any errors, only then can you think about using types such as Double?. Although, you probably don't want to store your year as a double, an int might be more appropriate. Or maybe it isn't; perhaps you want to store the errors, because that's what a user has entered. Some careful consideration is required here. Don't rush with the type system, let it work for you, thinking about which datatypes to use will help you design the rest of your code.
The issue here is the data coming from the excel, not your code who behave correctly.
Say you try using the T is double? then you double.tryParse(row) and when it fails you take the 4 first caracter of the string 2023g but what will happen if you have another property of type double? but expect only 2 or 3 numbers but the user put some dummy stuff how do you will manage that ? It's impossible.
Fix the Excel not your code ;)
Log the error, send a message to the user to fix the data :)

Programmatical naming variable c#

I have a large amount of nested foreach loops and I'm running out of variable names to use...
Could I do something like this :
//int i = 1
string "number"+i = new String("FirstElement");
I've seen some posts about this for languages such as C and javascript, but I don't know how to do it in C#.
In case you can't name variables after other variables : how could this problem otherwise be solved?
This problem could otherwise be solved by using meaningful variable names - running out of names would mean running out of concepts for what the thing is trying to achieve, which is hard to believe.
If your requirement is to work with a collection of variables, then put them in a collection; if it's to have n number of variables all strictly defined by name, then name them explicitly, and so on.
var a = new List<int>();
for(int i=0;i<100;i++)
{
a.Add(i);
}
Console.WriteLine(a[0]);
Console.WriteLine(a[1]);
etc....
This way you make list which contains 100 elements, you can access them by nameoflist[index]
A while back I asked a similar question:
Python - neat way of creating multiple objects?
Basically, if you have lots of very similar variables named things like variable_1, variable_2, etc, then thats normally a sign that you should be using an array or list of variables instead.
So instead of 10 separate string variables, create a list (or array) of strings.
The way you are doing will not work in C#. You can not create variables at run time. If you want
you have to use a list to store your variable name and value. Therefore you better create a class to hold name of the variable and value.
class Variable
{
string Name;
string Value;
}
Now create another class to hold variables
class VaraibleHolder
{
List<Variable> Variables;
VariableHolder()
{
Variables = new List<Variables>();
}
public void Add(Variable Vbl)
{
Variable vbl = Variables.SingleOrDefault(v=>v.Name == Vbl.Name);
if(vbl == null)
{
Variables.Add(vbl);
}
}
public void Remove(string VblName)
{
//this is a lamda expression.
Variable vbl = Variables.SingleOrDefault(v=>v.Name == VblName);
if(vbl != null)
{
Variables.Remove(vbl);
}
}
public Variable GetVariable(string VblName)
{
Variable vbl = Variables.SingleOrDefault(v=>v.Name == VblName);
return vbl;
}
}
So you can use Variable holder to create and store varaibles at runtime. Hope this will help you.

What is the best way to store static data in C# that will never change

I have a class that stores data in asp.net c# application that never changes. I really don't want to put this data in the database - I would like it to stay in the application. Here is my way to store data in the application:
public class PostVoteTypeFunctions
{
private List<PostVoteType> postVotes = new List<PostVoteType>();
public PostVoteTypeFunctions()
{
PostVoteType upvote = new PostVoteType();
upvote.ID = 0;
upvote.Name = "UpVote";
upvote.PointValue = PostVotePointValue.UpVote;
postVotes.Add(upvote);
PostVoteType downvote = new PostVoteType();
downvote.ID = 1;
downvote.Name = "DownVote";
downvote.PointValue = PostVotePointValue.DownVote;
postVotes.Add(downvote);
PostVoteType selectanswer = new PostVoteType();
selectanswer.ID = 2;
selectanswer.Name = "SelectAnswer";
selectanswer.PointValue = PostVotePointValue.SelectAnswer;
postVotes.Add(selectanswer);
PostVoteType favorite = new PostVoteType();
favorite.ID = 3;
favorite.Name = "Favorite";
favorite.PointValue = PostVotePointValue.Favorite;
postVotes.Add(favorite);
PostVoteType offensive = new PostVoteType();
offensive.ID = 4;
offensive.Name = "Offensive";
offensive.PointValue = PostVotePointValue.Offensive;
postVotes.Add(offensive);
PostVoteType spam = new PostVoteType();
spam.ID = 0;
spam.Name = "Spam";
spam.PointValue = PostVotePointValue.Spam;
postVotes.Add(spam);
}
}
When the constructor is called the code above is ran. I have some functions that can query the data above too. But is this the best way to store information in asp.net? if not what would you recommend?
This is a candidate for an immutable struct that "looks like" an enumeration:
(Also, I noticed you used the same id value for two of them, so I fixed that...
You can use the following just as you would an enumeration...
PostVoteTypeFunctions myVar = PostVoteTypeFunctions.UpVote;
and real nice thing is that this approach requires no instance storage other than a 4-byte integer (which will be stored on stack, since it's a struct). All hard-coded values are stored in the type itself... of which only one will exist per AppDomain...
public struct PostVoteTypeFunctions
{
private int id;
private bool isDef;
private PostVoteTypeFunctions ( ) { } // private to prevent direct instantiation
private PostVoteTypeFunctions(int value) { id=value; isDef = true; }
public bool HasValue { get { return isDef; } }
public bool isNull{ get { return !isDef; } }
public string Name
{
get
{ return
id==1? "UpVote":
id==2? "DownVote":
id==3? "SelectAnswer":
id==4? "Favorite":
id==5? "Offensive":
id==6? "Spam": "UnSpecified";
}
}
public int PointValue
{
get
{ return // Why not hard code these values here as well ?
id==1? PostVotePointValue.UpVote:
id==2? PostVotePointValue.DownVote
id==3? PostVotePointValue.SelectAnswer:
id==4? PostVotePointValue.Favorite:
id==5? PostVotePointValue.Offensive:
id==6? PostVotePointValue.Spam:
0;
}
}
// Here Add additional property values as property getters
// with appropriate hardcoded return values using above pattern
// following region is the static factories that create your instances,
// .. in a way such that using them appears like using an enumeration
public static PostVoteTypeFunctions UpVote = new PostVoteTypeFunctions(1);
public static PostVoteTypeFunctions DownVote= new PostVoteTypeFunctions(2);
public static PostVoteTypeFunctions SelectAnswer= new PostVoteTypeFunctions(3);
public static PostVoteTypeFunctions Favorite= new PostVoteTypeFunctions(4);
public static PostVoteTypeFunctions Offensive= new PostVoteTypeFunctions(5);
public static PostVoteTypeFunctions Spam= new PostVoteTypeFunctions(0);
}
It is difficult to tell from the fragment of code you have posted whether you expose any of the data outside the class.
If not, then this would work. However, if not, there are several issues:
If you are exposing the List, you should only ever return a copy of it as an IEnumerable<PostVoteType> using the yield keyword.
Make sure your PostVoteType is immutable, otherwise the references can be changed and the fields used might be altered
Looking at your code, it looks like you're just trying to create a set of objects that really just put the enum PostVotePointValue into some sort of list. I.e. you already have what you need defined in just the enum itself. I would encourage you to not define the same information in two places (this data store you are asking for and the enum). This is common mistake I see people make. They create a lookup table/list, then create an enum that mirrors the rows of the table and that means they have to modify two places for any change to the list.
If PostVotePointValue isn't an enum but just some constants or if there is more info you are planning on packing in, then this isn't relevant.
Here's some examples of how to work with Enums as 'lists' from http://www.csharp-station.com/Tutorials/Lesson17.aspx
// iterate through Volume enum by name
public void ListEnumMembersByName()
{
Console.WriteLine("\n---------------------------- ");
Console.WriteLine("Volume Enum Members by Name:");
Console.WriteLine("----------------------------\n");
// get a list of member names from Volume enum,
// figure out the numeric value, and display
foreach (string volume in Enum.GetNames(typeof(Volume)))
{
Console.WriteLine("Volume Member: {0}\n Value: {1}",
volume, (byte)Enum.Parse(typeof(Volume), volume));
}
}
// iterate through Volume enum by value
public void ListEnumMembersByValue()
{
Console.WriteLine("\n----------------------------- ");
Console.WriteLine("Volume Enum Members by Value:");
Console.WriteLine("-----------------------------\n");
// get all values (numeric values) from the Volume
// enum type, figure out member name, and display
foreach (byte val in Enum.GetValues(typeof(Volume)))
{
Console.WriteLine("Volume Value: {0}\n Member: {1}",
val, Enum.GetName(typeof(Volume), val));
}
}
}
You should be able to adapt the above into an approach that will give you a list that you can use for databinding if you need it.
I am wondering why you could not just use a simple enum for this?
public enum PostVoteType
{
UpVote = 0,
DownVote = 1,
SelectAnswer = 2,
Favorite = 3,
Offensize = 4,
Spam = 5
}
"Never" is a very hard word indeed.
In your particular case you are asserting that not only is your PostVoteType data absolute and immutable, but so is the container collection. Frankly I don't believe you can know that, because you are not the business (your interpretation of requirement is imperfect) and you are not psychic (your knowledge of the future is imperfect).
I would suggest that you always store any data which cannot be expressed as an enumeration in some kind of repository. Where you expect relational and/or transactional and/or mutable needs that means a database, if you expect high read to write ratio that can be a config file (which I believe this case should be).
Edit: In terms of memory persistance I agree with others that the cache is the best place to store this, or rather in a domain object which is backed by cache.
Aside: your construction of PostVoteTypes is horrible - strongly suggest you want a refactor :)
If it doesn't change, is commonly accessed, and is the same for all users, then the .NET cache is the proper place. Have a property that yields these values. Inside, the property checks the cache for this list and returns the stored value; otherwise, it constructs it from scratch, adds to the cache, and returns the value.
This should still probably be configured in the database though, even if you cache it. I imagine that you'll need to use these value in conjunction with other data in your DB.
When you need to often access the same data, and need not to store it into the underlying database, and that this data is about the same in every situation the application may encounter, then I suggest to use caching. Caching is born from these requirements. Caching is normally the fastest way to providing data as they are always kept in memory or something similar to ease and to make the access easier by the application.
Here is a nice caching tool provided with Microsoft Enterprise Library, the Caching Application Block.
I think it is worth to take the time to learn how to use it effectively.
create a singleton class.

c# looping object creation

I'm very new with c#, and was previously attempting to ignore classes and build my small program structurally more similar to PHP. After reaching a road block, I'm trying to start over and approach the problem properly OO. I'm taking a long file, and in a loop, every time certain conditions are met, I want to make a new object. How can I have it create a new object, without having to specify a unique name?
Referral ObjectName = new Referral(string, string, int);
Secondly, once this is done, and the strings & int set their appropriate object properties, how can i unique-ify the class by one property, and then sort the class by another?
I'm sorry if these are basic questions, I have spent a large, large amount of time first trying to figure it out on my own with google, and a textbook. If only C# would allow multi-dimensional arrays with different types!
Thank you so much!
PS. I do mean to extract a list of unique objects.
All these answers, while helpful, seem to involve creating a shadow set of IEnumerables. Is there no way to do this with the class itself?
Trying the first solution, provided by Earwicker, adding each object to a List from within the loop, when I try to Write a property of the element to the console, i get the ClassName+Referral. What could I be doing wrong?--solved. still needed .property
still working. . .
C# does allow untyped arrays. All objects are derived ultimately from object, so you use an array or container of objects. But it's rarely necessary. How many types of object do you have?
Within the loop block, you can create an object exactly as you do in that line of code (except with the syntax fixed), and it will be a new object each time around the loop. To keep all the objects available outside the loop, you would add it to a container:
List<Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals.Add(r);
Suppose Referral has a numeric property called Cost.
referrals.Sort((l, r) => l.Cost - r.Cost);
That sorts by the cost.
For ensuring uniqueness by some key, you may find it easier to pick a more suitable container.
Dictionary<string, Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals[str1] = r;
This stores the referral in a "slot" named after the value of str1. Duplicates will overwrite each other silently.
First, you're going to need to spend some time familiarizing yourself with the basics of the language to be productive. I recommend you take a little time to read up on C# before getting in too deep - otherwise you'll spend a lot of your time spinning your wheels - or reinventing them :)
But here's some info to get you started.
Typically, in C# you create classes to represent elements of your program - including those that are used to represent information (data) that your program intends to manipulate. You should really consider using one, as it will make data manipulation clearer and more manageable. I would advise avoiding untyped, multi-dimensions array structures as some may suggest, as these rapidly become very difficult to work with.
You can easily create a Referall class in C# using automatic properties and a simple constructor:
public class Referall
{
// these should be named in line with what they represent...
public string FirstString { get; set; }
public string AnotherString { get; set; }
public int SomeValue { get; set; }
public Referall( string first, string another, int value )
{
FirstString = first;
AnotherString = another;
SomeValue = value;
}
}
You can add these to a dictionary as you create them - the dictionary can be keyed by which ever property is unique. Dictionaries allow you to store objects based on a unique key:
Dictionary<string,Referall> dict = new Dictionary<string,Referall>();
As you process items, you can add them to the dictionary:
Referall ref = new Referall( v1, v2, v3 );
// add to the dictionary, keying on FirstString...
dict.Add( ref.FirstString, ref );
If you need to sort items in the dictionary when you're done, you can use LINQ in C# 3.0:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString );
You can sort by multiple dimension using ThenBy() as well:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString )
.ThenBy( x => x.SomeValue );
List<Referral> referrals = new List<Referral>();
for (...)
{
referrals.Add(new Referral(string1, string2, number1));
}
Then, if you're using Linq (which I highly suggest), you can do this:
IEnumerable<Referral> sorted = referrals.OrderBy(x => x.string1).ThenBy(x => x.string2);
Otherwise, you can use the Sort() method on List<Referral>.
You can create an object without a reference, but you won't have any access to it later:
new Referral(string, string, int);
If you wish to put them in an array/list, these different types need to have a common base class. This is called polimorfism, which is a very important concept in OO programming.
You cannot ignore classes while using c#. Don't resist the change!
Do you really not need to create a class here? Do you really not need to give it a name? C# does allow loose typing, but type safety is a good thing.
I don't fully understand what you're trying to do. But maybe LINQ is what you're looking for. There's tons of documentation around, but as a quick 'teaser' have a look at the 101 Linq samples on MSDN
C# includes a wonderful feature called "iterator blocks". What you want to do is use the yield keyword to create an Enumerable of your Referal object, something like this (not that I'm making the file format and property names up, because you didn't share that):
public class Referral
{
public Guid id { get; private set; } // "uniquify"
public int ReferringId { get; set; }
public string ReferrerText { get; set; }
public string ReferrerDescription { get; set; }
private Referral()
{
id = new Guid();
}
private Referral(string Text, string Description, int ReferringId) : this()
{
this.ReferrerText = Text;
this.ReferrerDescription = Description;
this.ReferringId = ReferringId;
}
public static IEnumerable<Referral> GetReferrals(string fileName)
{
using (var rdr = new StreamReader(fileName))
{
var next = new Referrer();
int state = 0;
string line;
while ( (line = rdr.ReadLine() ) != null)
{
switch (state)
{
case 0:
next.ReferrerText = line;
state = 1;
break;
case 1:
next.ReferrerDescription = line;
state = 2;
break;
case 2:
next.ReferringId = int.Parse(line);
yield return next;
next = new Referral();
state = 0;
break;
}
}
}
}
}
Now you want to sort the referrals and presumable enumerate over them for some purpose. You can do that easily like this:
foreach (var referral in Referral.GetReferrals(#"C:\referralfile.txt").OrderBy( r => r.Text ) )
{
OutputReferral(referral);
}

How to get name of a class property?

Is there anyway I can get the name of class property IntProperty?
public class ClassName
{
public static int IntProperty { get { return 0; } }
}
//something like below but I want to get the string of "IntProperty"
ClassName.IntProperty.GetType().Name
Basically what I want to do is to dynamically save property name string into the database, and later on retrieve it from the database and invoke the property dynamically.
Seems like what I am looking for is similar to duck typing I think.
Thanks!
UPDATED:
This is the actual code. This is more like a workflow kind of thing. But each task is defined as property of a class (class is used to group tasks).
public class ApplicationTask
{
public static Task<string> SendIncompleteNotification
{
get
{
return new Task<string>
(
a => Console.WriteLine("Sample Task")
, "This is a sample task which does nothing."
);
}
}
}
So, the code will be able to retrieve the full name of the class and property something like: namespace.ApplicationTask.SendIncompleteNotification and save this into the database. Later on, the code will read the string and dynamically create the task and pass it into another to execute.
With C#6.0 you can get it by
nameof(ClassName.IntProperty)
I think that the use of the GetProperty method in this case, is redundant, because you need to know the property name to call the method.
You could loop through your properties and extract its name:
foreach (PropertyInfo p in typeof(ClassName).GetProperties())
{
string propertyName = p.Name;
//....
}
The result of ClassName.IntProperty is just an integer value. As soon as it's executed and the result is returned, there's no trace of it having come from IntProperty.
If you're using .NET 3.5 you can use an expression tree instead, usually created via a lambda expression:
Expression<Func<int>> exp = () => ClassName.IntProperty;
You can then compile and execute the expression and separately find out what it's doing (retrieving IntProperty in this case). I'm not really sure whether this is suitable for what you want to do though.
If you do work out how to save the property name in the database, then GetProperty is the way to go on the retrieval front.
Perhaps if you could give more context in the question in terms of how you want to use this, we could help more. You've shown just an expression - if you could show it in terms of where you'd be using it, that would be great.
EDIT: You've expanded the property, but not how it's being called. Do you need to call it directly, rather than just fetching the list of properties using Type.GetProperties and storing the list of property names in the database?
Again, if you could show the code which calls the property, and how you want it to interact with the database, we may be able to make more progress.
Type objectType = this.GetType();
PropertyInfo property = objectType.GetProperty("intProperty");
System.Console.Write(property.Name);
Is this what you need?
You can simply use nameof(ClassName.IntProperty)
It will give you "IntProperty"
I came across this, and it seems very helpful for getting property name. (C++)
#define getVarName(varName,holder) sprintf(holder, "%s", #varName)
int main() {
int var = 100; // just any type of identifier
char name[100]; // it will get the variables name
getVarName(var, name);
puts(name);
return 0;
}
ref: http://zobayer.blogspot.com/2010/05/c-fun-get-variables-name.html

Categories