Modifying the string list using reflection - c#

Say, I have a class User which has (string FirstName, List siblings)
I want to modify the properties of the user.
Let's assume that I want to replace the strings with b instead of a.
user : {
firstname: "Rager",
siblings : {
"stalin",
"Marx"
} }
using reflection I need to read the individual strings and the following would be the output object.
user : {
firstname: "Rbger",
siblings : {
"stblin",
"Mbrx"
} }
Let's consider the below function
private object modifyObject(object t){
foreach(var propertyInfo in t.GetType.GetProperties(){
var stringToBeModified = propertyInfo.GetValue(t,null);
propertyInfo.SetValue(t, stringToBeModified.replace("a","b"),null)
}
}
The above code works fine when modifying the firstName. But dont know how to modify the strings in siblings.
I thought I will make use of the 3rd property (optional index value for the indexed properties). But it looks like the whole property was not indexed.
for siblings, propertyInfo.GetValue(t,null) gives 2 strings.
[0] -- stalin
[1] -- Marx.
Can anyone tell me how I can modify the above 2 strings after getting the value using propertyInfo.GetValue(t,null)?

You can simply cast the value as List<string> and update as desired
eg
List<string> list = (List<string>)propertyInfo.GetValue(t,null);
list[0] = list[0].replace("a","b");
above sample is assuming the propertyInfo of siblings which is of type List<string>, you may adjust as needed.

Related

How to manipulate objects after JSON list deserialization

I'm trying to work with JSON files to store a Class and I'm stuck with the deserialization.
I'm using the following NameSpace:
using System.Text.Json.Serialization;
I have a very simple class, made of 2 properties:
public EnumOfType Type { get; set; }
public double Price { get; set; }
I have 4 instances of this classe that I store in a list. When quiting the application, this list is saved in a JSON file.
string jsonString;
jsonString = JsonSerializer.Serialize(myListOfInstances);
File.WriteAllText(FileName, jsonString);
When I'm opening the Application, I want the JSON file to be loaded to recreate the instances.
I'm using the following method, which apparently works well.
string jsonString = File.ReadAllText(FileName);
myListOfInstances = JsonSerializer.Deserialize<List<MyClass>>(jsonString);
So far so good. When I check the content of the list, it is correctly populated and my 4 instances are there.
But then... how to use them?
Before the JSON, I was creating each instance (for example:)
MyClass FirstInstance = New MyClass();
FirstInstance.Type = EnumOfType.Type1;
FirstInstance.Price = 100.46;
Then I could manipulate it easily, simply calling FirstInstance.
myWindow.Label1.Content = FirstInstance.Price.ToString("C");
FirstInstance.Method1...
Now that the instances are in my list, I don't know how to manipulate them individually because I don't know how to call them.
It's probably obvious to most, but I'm still in the learning process.
Thank you for your help,
Fab
Based on how you have loaded the JSON file into your program, it looks like your variable myListOfInstances already contains all four MyClass objects ready to go. At this point you can use List accessors (or Linq if you want to be fancy) and do things such as the following:
myListOfInstances[0] //Gives you the first item in the list accessed by index
myListOfInstances.First() //Gives you the first item in the list (using linq)
foreach(var item in myListOfInstances) {
// this will iterate through all four items in the list storing each instance in
//the 'item' variable
}
etc...
EDIT: From my comment below. If you need to access values in a a list directly, you can search for specific conditions in the list using linq with the 'Where' method. The syntax is something like this:
myListOfInstances.Where(x => x.Property == SomePropertyToMatch)

use the name of the field instead of index in list array in C#

I have a getvalue object that contains a price list which consists of 5 items. I need to get the value of one of the elements. I can get the value by index:
return (getValue1.ValuationPrices[4].Value.ToString());
Instead of using 4 (the index) I would like to use the name of the field. Can I do that?
More detail:
I want to say if PriceType is "Wholesale" return the value that is 18289
that is the answer to this question:
foreach (var item in getValue1.ValuationPrices)
{
if (item.PriceType == ServiceReference1.PriceType.Wholesale)
{
carValue= item.Value.ToString();
}
}
You can either change your array to Dictionary<string, yourType> or use LINQ to perform linear search for your object by name:
return getValue1.ValuationPrices.First(x => x.Name == "myName").Value.ToString();
You could do this by adding an indexer property to the ValuationPrices type.
public ValuationPrice this[string name]
{
get
{
return this.First(n => n.Name == value);
}
}
Then you would be able to write getvalue1.ValuationPrices["fieldName"].
The implementation of the indexer property will vary depending on the internal structure of your classes, but hopefully this gives you some idea of the syntax used to implement the indexer.
The screenshot helped quite a bit... people can't guess what your classes look like internally. Your comment to Marcin indicates that PriceType might be an enumeration. So assuming:
PriceType is actually an enum, not a string
The PriceType you're searching for is guaranteed to be in that collection at once and one time only
This should work:
return getValue1.ValuationProces.Single(x => x.PriceType == PriceType.WholeSale).Value.ToString();
This is basically the same as Marcin's - if I'm right about PriceType being an enum and this works, then you should just accept his answer and move on.

Retrieving item from list

I'm having some problems retrieving information from a list.
In this case I'd like to get the name from a list, eventually I want it turned into a string. This is what I have:
public string ShowName(int patientcode)
{
List<ExtendPatientInfo> patientdata = dk.RetrieveList(patientcode);
string name = patientdata. <What here?>
return name;
}
In the class ExtendPatientInfo I have this, which I think is allright:
private string name;
public ExtendPatientInfo(string name)
{
this.name = name;
}
public string Name
{
get
{
return name;
}
}
I tried using a few things. Like Contains, Find, FindIndex and where. But none of these worked for me because I probably messed something up somewhere. Anybody that can help me?
You have to choose the patient. If it is all the same data for the patient, then you can use LINQ's First
patientdata.First().Name
But, if they are all different, then you could map the list to only have Names
patientdata.Select(x=>x.Name)
At which point, you would still need to iterate through the list to display each name or whatever you need.
As Henk points out, if this is always going to be a list of one item, then you could use
patientdata.Single().Name
*The caveat with Single is from MSDN
Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
Well you have a list of object and you want to show properties of each object, then you have to access each object in the list and then access it properties. Something like:
foreach(var item in patientdata)
{
Console.WriteLine(item.Name);
//rest of the fields
}
If you want to select a single object from your list then you cause use First / FirstOrDefault , Single / SingleOrDefault depending on your need. But you need an individual object to access it properties. You can't access a property directly from a list.
var item = patientData.FirstOrDefault();
if(item != null)
Console.WriteLine(item.Name);
Try
string name = string.Empty;
var pd = patientData.FirstOrDefault();
if(pd != null)
name = pd.Name
This code gets the first item returned or null.
If it isn;t null it retrieves the Name property value into string variable name.
Incidentally, if you don;t want to learn linq right now you can access List<> via index like:
patientData[0].Name
You will still want to check that patientData[0] is not null before checking the Name property.
You probably want to use Linq. Linq allows you to cycle through a list easily and get what you want.
For example, if you want the patient named "Johan":
ExtendPatientInfo patient = patientdata.Where(x => x.Name == "Johan").FirstOrDefault();
string name = patient.Name;
If I understand your question, you are looking for something like this
ExtendPatientInfo patient =
patientdata.FirstOrDefault(x => x.patientcode == patientcode);
return
(patient != null)
? patient.Name
: null

List of Lists in datagridview

I have a list of employees:
List<Person> Employees;
the class Person has two properties:
a name, and a List-of number of widgets they made each hour(limited to 24 hours)
Now i want to display this array in a datagridview: i guess the display should look something like:
employees, 1,2,3,4,....,24
anna , 0,10,5,15,..,5
jeff , 1,6,2,......,4
and so on.
right now i just make a datasource=employees binding, and this sucessfully displays the name, but it doesn't even touch the List property. is there some trick to making a list of ints into a property? or maybe i should make a separate property for each hour that will interface with the list?
a simple option is to create a "get" property inside the Person class that returns the list of integers as a single string, like you want to output.
public string NumbersList
{
get
{
return string.Join(", ", this.List);
}
}
and when you bind, use this property instead of the list so it will show the long string you want ("1,3,4")

Store variables in list/array and loop through later c#

Sorry, I think I was not clear earlier. I am trying to do as O.R.mapper says below- create a list of arbitrary variables and then get their values later in foreach loop.
Moreover, all variables are of string type so I think can come in one list. Thanks.
Is there a way to store variables in a list or array then then loop through them later.
For example: I have three variables in a class c named x,y and Z.
can I do something like:
public List Max_One = new List {c.x,c.y,c.z}
and then later in the code
foreach (string var in Max_One)
{
if ((var < 0) | (var > 1 ))
{
// some code here
}
}
Is there a particular reason why you want to store the list of variables beforehand? If it is sufficient to reuse such a list whenever you need it, I would opt for creating a property that returns an IEnumerable<string>:
public IEnumerable<string> Max_One {
get {
yield return c.x;
yield return c.y;
yield return c.z;
}
}
The values returned in this enumerable would be retrieved only when the property getter is invoked. Hence, the resulting enumerable would always contain the current values of c.x, c.y and c.z.
You can then iterate over these values with a foreach loop as alluded to by yourself in your question.
This might not be practical if you need to gradually assemble the list of variables; in that case, you might have to work with reflection. If this is really required, please let me know; I can provide an example for that, but it will become more verbose and complex.
Yes, e.g. if they are all strings:
public List<string> Max_One = new List<string> {c.x,c.y,c.z};
This uses the collection initializer syntax.
It doesn't make sense to compare a string to an int, though. This is a valid example:
foreach (string var in Max_One)
{
if (string.IsNullOrEmpty(var))
{
// some code here
}
}
If your properties are numbers (int, for example) you can do this:
List<int> Max_One = new List<int> { c.x, c.y, c.Z };
and use your foreach like this
foreach(int myNum in Max_One) { ... } //you can't name an iterator 'var', it's a reserved word
Replace int in list declaration with the correct numeric type (double, decimal, etc.)
You could try using:
List<object> list = new List<object>
{
c.x,
c.y,
c.z
};
I will answer your question in reverse way
To start with , you cannot name your variable with "var" since it is reserved name. So what you can do for the foreach is
foreach (var x in Max_One)
{
if ((x< 0) || (x> 1 ))
{
// some code here
}
}
if you have .Net 3.0 and later framework, you can use "var" to define x as a member of Max_One list without worrying about the actual type of x. if you have older than the version 3.0 then you need to specify the datatype of x, and in this case your code is valid (still risky though)
The last point (which is the your first point)
public List Max_One = new List {c.x,c.y,c.z}
There are main thing you need to know , that is in order to store in a list , the members must be from the same datatype, so unless a , b , and c are from the same datatype you cannot store them in the same list EXCEPT if you defined the list to store elements of datatype "object".
If you used the "Object" method, you need to cast the elements into the original type such as:
var x = (int) Max_One[0];
You can read more about lists and other alternatives from this website
http://www.dotnetperls.com/collections
P.s. if this is a homework, then you should read more and learn more from video tutorials and books ;)

Categories