Using a variable inside a member of an object [duplicate] - c#

This question already has answers here:
Get property value from string using reflection
(24 answers)
Closed 8 years ago.
I am pulling several elements of data out of an object in C#. They are all in the same 'place' within the object, as in:
objectContainer.TableData.Street.ToString());
objectContainer.TableData.City.ToString());
objectContainer.TableData.State.ToString());
objectContainer.TableData.ZipCode.ToString());
I would LIKE to use a foreach loop to pull them all and be able to add more by adding to the array.
string[] addressFields = new string[] { "Street", "City", "State", "ZipCode" };
foreach(string add in addressFields)
{
objectContainer.TableData.{add}.ToString());
}
Can this be done, and if so, what is the correct procedure?

You would need to use reflection to achieve this:
var type = objectContainer.TableData.GetType();
foreach(var addressFieldName in addressFieldNames)
{
var property = type.GetProperty(addressFieldName);
if(property == null)
continue;
var value = property.GetValue(objectContainer.TableData, null);
var stringValue = string.Empty;
if(value != null)
stringValue = value.ToString();
}
Please note: This code is pretty defensive:
It will not crash if no property with the specified name exists.
It will not crash if the value of the property is null.

You can use Reflection to do this.
string[] addressFields = new string[] { "Street", "City", "State", "ZipCode" };
foreach(string add in addressFields)
{
var myVal = objectContainer.TableData.GetType().GetProperty(add).GetValue(objectContainer.TableData).ToString();
}
Note that this doesn't allow for array values that don't have a corresponding property on objectContainer.TableData.

Related

Use variable name as foreach iteration variable and set it's value [duplicate]

This question already has answers here:
Why are assignment operators (=) invalid in a foreach loop?
(10 answers)
Closed 3 years ago.
I have four boolean variables. I have initalised the list radioBtns with the name of each of these variables as strings.
I want to loop through each of the strings in the list and set each boolean variable (which each have the same name as the strong) to true.
I receive this error though:
Cannot assign to 'Btn' because it is a 'foreach iteration variable'
bool Q1Button1_True, Q2Button1_True, Q3Button1_True, Q4Button1_True;
List<string> radioBtns = new List<string>(new string[] { "Q1Button1_True", "Q2Button1_True", "Q3Button1_True", "Q4Button1_True" });
foreach (string Btn in radioBtns)
{
Btn = true;
}
Instead of four different variables, you should use an array:
bool[] QButton_True = new bool[4];
for (int i = 0 ; i < 4 ; i++) {
QButton_True[i] = true;
}
Instead of referring to them as Q1Button_True, Q2Button_True..., you refer to them as QButton_True[0], QButton_True[1]...
You could use reflection for this, but it might be overkill for this scenario.
If you are simply setting all variables to true, you might want to just set them on the source.
bool Q1Button1_True = true;
bool Q2Button1_True = true;
bool Q3Button1_True = true;
bool Q4Button1_True = true;
Also, if this is something that will grow, let's say to Qn then you might want to have an array, where instead of Q1Button1_True you would have Button1_True[1].
I am assuming you will be doing this is multiple parts of your application, so it might be a wise choice to have some "dynamic" setters. In this case, you can use reflection:
bool Q1Button1_True, Q2Button1_True, Q3Button1_True, Q4Button1_True;
List<string> radioBtns = new List<string>(new string[] { "Q1Button1_True", "Q2Button1_True", "Q3Button1_True", "Q4Button1_True" });
foreach (string Btn in radioBtns)
{
bool buttonVar = this.GetType().getProperty(Btn).getValue(this, null);
buttonVar = true;
}
Another way of doing it is to use something like this:
bool Q1Button1_True, Q2Button1_True, Q3Button1_True, Q4Button1_True;
List<string> radioBtns = new List<string>(new string[] { "Q1Button1_True", "Q2Button1_True", "Q3Button1_True", "Q4Button1_True" });
foreach (string Btn in radioBtns)
{
PropertyInfo buttonVar = this.GetType().GetProperty(Btn);
buttonVar.SetValue(this, true, null);
}
Hope this helps!

Query Json Object dynamically

I am trying to implement a dynamic condition on a JSON Object.
After searching for a while, I am not able to find any resources which can meet my needs.
In the below fashion, I am getting the JsonObject dynamic string into jsonObject variable.
string inputFromAPI = client.GetStringAsync(URL).Result;
dynamic jsonObject = JValue.Parse(inputFromAPI);
I now have a condition which can change on need basis.For example I can have a condition which says
"inputFromAPI.DidWeCharge == true && inputFromAPI.DidWeHold == false"
The above line can change on the fly. Any inputs how to address this will be greatly appreciated.
I can't comment for clarification (don't have the rep yet), but if you need to be able to read the property name because it's changing you can do this. You would have to know the name though.
var JSONobj = JObject.Parse(json);
foreach (JToken child in JSONobj.Children())
{
var prop = child as JProperty;
var propertyName = prop.Name; // this will give you the name of the property
if (propertyName == "DidWeCharge")
{
var value = prop.Value; // Do something here with value?
}
if (propertyName == "DidWeHold")
{
var value = prop.Value; // Do something here with value?
}
var propertyType = prop.Value.Type; // this return the type as a JTokenType enum.
}
I don't know how nested your JSON is, so you may have to traverse further down with another foreach on the child by doing child.Children().
You can use ExpandoObject:
var expandoObj = JsonConvert.DeserializeObject<ExpandoObject>(jsonObject);
expandoObj.yourProperty
JsonConvert is from Newtonsoft.Json package.
You may be able to use Jpath:
using Newtonsoft.Json -
....
var json = #"
{
stuff : [
{
value : 1
},
{
value : 2
}
]
}";
var token = JToken.Parse(json);
var something = token.SelectTokens("$.stuff[?(#.value == 1)]").ToList();

Sorting a class string field property with numerical value [duplicate]

This question already has answers here:
Sorting of list contained strings having alphabetic/numeric
(2 answers)
Closed 8 years ago.
I have a class with one property "Name" containing names like "1_[AnnualRevenue]","2_[ResellerType]","3_xxx"....
my class is like
class xxx
{
private string fileName;
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
}
And I am assigning the values to the object of the class. like xxx.FileName="1_[AnnualRevenue]";
Now I have a list class. And now sort the list according to this class property.
Now I want to sort the field according to the numeric order, I mean 1 first 2 second and so on.
And then write it to filestream.
Could any body help me with this.
Thanks in advance.
Since the property is a String but you want to sort it numerically, probably the best way would be to implement IComparable on your class and then put your custom sort code in the CompareTo method. Then you don't have to write a more complex Lambda statement each time you want to Sort a list, you can just call the Sort() method on the list.
You can also handle cases where the FileName property does not contain an underscore or is null, rather than getting exceptions in your OrderBy code (which is what would happen with most of the other answers).
I made a couple of other changes also - override the ToString method so you can easily display the value to the console window, and used Automatic property syntax for the FileName property so we can remove the backing field:
class xxx : IComparable<xxx>
{
public string FileName { get; set; }
public int CompareTo(xxx other)
{
// Short circuit if any object is null, if the
// Filenames equal each other, or they're empty
if (other == null) return 1;
if (FileName == null) return (other.FileName == null) ? 0 : -1;
if (other.FileName == null) return 1;
if (FileName.Equals(other.FileName)) return 0;
if (string.IsNullOrWhiteSpace(FileName))
return (string.IsNullOrWhiteSpace(other.FileName)) ? 0 : -1;
if (string.IsNullOrWhiteSpace(other.FileName)) return 1;
// Next, try to get the numeric portion of the string to compare
int thisIndex;
int otherIndex;
var thisSuccess = int.TryParse(FileName.Split('_')[0], out thisIndex);
var otherSuccess = int.TryParse(other.FileName.Split('_')[0], out otherIndex);
// If we couldn't get the numeric portion of the string, use int.MaxValue
if (!thisSuccess)
{
// If neither has a numeric portion, just use default string comparison
if (!otherSuccess) return FileName.CompareTo(other.FileName);
thisIndex = int.MaxValue;
}
if (!otherSuccess) otherIndex = int.MaxValue;
// Return the comparison of the numeric portion of the two filenames
return thisIndex.CompareTo(otherIndex);
}
public override string ToString()
{
return FileName;
}
}
Now, you can just call Sort on your list:
List<xxx> list = new List<xxx>
{
new xxx {FileName = "13_a"},
new xxx {FileName = "8_a"},
new xxx {FileName = null},
new xxx {FileName = "1_a"},
new xxx {FileName = "zinvalid"},
new xxx {FileName = "2_a"},
new xxx {FileName = ""},
new xxx {FileName = "invalid"}
};
list.Sort();
Console.WriteLine(string.Join("\n", list));
// Output (note the first two are the empty string and the null value):
//
//
// 1_a
// 2_a
// 8_a
// 13_a
// invalid
// zinvalid
You can use LINQ to do that for you
List<xxx> orderedList = unOrderedList.OrderBy(o => Convert.ToInt32(o.FileName.Split('_').First())).ToList();
Editted the answer on behalf of the comments - pointing out that indeed we need to convert to integers to order correctly.
You can do like following to sort the list:
List<xxx> list = new List<xxx>
{
new xxx { FileName = "3_a" },
new xxx { FileName = "1_a" },
new xxx { FileName = "2_a" },
new xxx { FileName = "8_a" }
};
var sorted = list.OrderBy(it => Convert.ToInt32(it.FileName.Split('_')[0]));//using System.Linq;
And you can write the list to disk file as below:
using (TextWriter tw = new StreamWriter("C:\\FileNames.txt"))
{
foreach (var item in sorted)
{
tw.WriteLine(item.FileName.ToString());
}
}

How to get a max value of a field from mongo cursor in C#

The complete method should be generic like
public string strGetMaxValue(string strDBName, string strCollectionName, string strKey)
{
// in this method if pass some prms it should give max value
}
The one i tried is
string strMaxValue = "";
MongoServer objServer = this.ConnectToServer();
if ((strDBName != null || strDBName != "") && (strCollectionName != null || strCollectionName != ""))
{
string[] strArrays = new string[1];
strArrays[0] = strKey;
//MongoCursor<BsonDocument> objCursor = objServer.GetDatabase(strDBName).GetCollection(strCollectionName).Find(query).SetSortOrder(SortBy.Descending(strArrays)).SetLimit(1);
var objCursor = objServer.GetDatabase(strDBName).GetCollection(strCollectionName).FindAll().SetSortOrder(SortBy.Descending(strArrays)).SetLimit(1).ToArray();
}
In that objCursor i m getting that document which i need.
i want to extract that field value and needs to send it as return parameter.
The method should be generic as such the key value may a field in nested document also.
how to achieve this.?
The method you are looking for is SetFields(params string[] fields) - it can be called on a cursor. It will limit your result set to just the fields you pass in (array) as well as the id. You can then index the field using the []
var result = server
.GetDatabase(strDBName)
.GetCollection(strCollectionName)
.FindAll()
.SetSortOrder(SortBy.Descending(new [] {strKey}))
.SetFields(new [] {strKey}) // The way to wrap something in an array for reference
.SetLimit(1)
.FirstOrDefault(); // Will return null if there are no rows
// There is a chance that we have no results
if (result != null)
// You might want to make sure this is a string / add the datatype
// as a Generic T to your function
return result[strKey].AsString;
else
return null;

How to get string list of Enum descriptions? [duplicate]

This question already has answers here:
Enum ToString with user friendly strings
(25 answers)
Closed 4 years ago.
How can I get a List of an Enum's values?
For example, I have the following:
public enum ContactSubjects
{
[Description("General Question")]
General,
[Description("Availability/Reservation")]
Reservation,
[Description("Other Issue")]
Other
}
What I need to be able to do is pass ContactSubject.General as an argument and it returns the List of the descriptions.
This method needs to work with any Enum, not just ContactSubject (in my example). The signature should be something like GetEnumDescriptions(Enum value).
Something like that may work:
private static IEnumerable<string> GetDescriptions(Type type)
{
var descs = new List<string>();
var names = Enum.GetNames(type);
foreach (var name in names)
{
var field = type.GetField(name);
var fds = field.GetCustomAttributes(typeof(DescriptionAttribute), true);
foreach (DescriptionAttribute fd in fds)
{
descs.Add(fd.Description);
}
}
return descs;
}
however you may review some logic there: such as is it ok to start of names? how are you going to handle multiple Description attributes? What if some of them are missing - do you want a name or just skip it like above? etc.
just reviewed your question. For the VALUE you would have something like that:
private static IEnumerable<string> GetDescriptions(Enum value)
{
var descs = new List<string>();
var type = value.GetType();
var name = Enum.GetName(type, value);
var field = type.GetField(name);
var fds = field.GetCustomAttributes(typeof(DescriptionAttribute), true);
foreach (DescriptionAttribute fd in fds)
{
descs.Add(fd.Description);
}
return descs;
}
however it is not possible to place two Description attributes on single field, so I guess it may return just string.

Categories