Converting string to the name of a class member c# - c#

Suppose i have the following class and i have an object (let it be called "obj1") created of it with some values. -
public class parameters
{
public string TYPE { get; set; }
public string label { get; set; }
public string prev { get; set; }
}
parameters obj1 = new parameters();
obj1.TYPE = "asdf";
suppose i have a string denoting one of the member names
string member_name = "TYPE";
how can i access the value of whatever name is there in the string of the object obj1 based ?
var val = obj1.member_name ?

You can get it using reflection:
var propertyInfo = typeof(parameters).GetProperty(member_name);
var propertyValue = propertyInfo.GetValue(obj1) as string;

Related

Get the value from object of a class by property name dynamically in c#

I want to write a method that should return the value from an object for the specified property.
public class MyClass
{
public int a { get; set; }
public int b { get; set; }
public int c { get; set; }
public int d { get; set; }
}
public int GetValue(string field)
{
MyClass obj=new MyClass();
obj=FromDb(); //get value from db
dynamic temp=obj;
return temp?.field;
}
The above code is only to demonstrate to what I am looking for.
Here I want to pass the property name (i.e a/b/c/d as per my above code) as an input to the method GetValue and it should return the value of that property.
This code is compiling successfully, but in run time it will search for the property name field not the value of field variable.
Any suggestions or workaround will be appreciated.
You can use reflection to get the value:
public int GetValue(string field)
{
MyClass obj = new MyClass();
obj = FromDb(); //get value from db
var property = obj.GetType().GetProperty(field);
return (int)property.GetValue(obj);
}

C# get property value from object using custom attribute

I have this POCO class with properties that use a custom attribute:
Application status flags POCO class
public class ApplicationStatusFlags
{
public int ApplicationId { get; set; }
[SectionFlag("APPLICANTPERSONALDETAILS")]
public bool PersonalDetailsStatus { get; set; }
[SectionFlag("APPLICANTECREGISTRATION")]
public bool EcRegistrationStatus { get; set; }
[SectionFlag("APPLICANTCV")]
public bool CvUpload { get; set; }
[SectionFlag("APPLICANTSTATEMENT")]
public bool IceAttributeStatement { get; set; }
[SectionFlag("APPLICANTCPD")]
public bool CpdUpload { get; set; }
[SectionFlag("APPLICANTORGCHART")]
public bool OrgChartUpload { get; set; }
[SectionFlag("APPLICANTSPONSORDETAILS")]
public bool SponsorDetails { get; set; }
}
Section flag attribute class
[AttributeUsage(AttributeTargets.All)]
public class SectionFlagAttribute : Attribute
{
/// <summary>
/// This constructor takes name of attribute
/// </summary>
/// <param name="name"></param>
public SectionFlagAttribute(string name)
{
Name = name;
}
public virtual string Name { get; }
}
I'm trying to get the value of one of these properties by using a string with the section flag name.
So if var foo = "APPLICANTSPONSORDETAILS" I would get the boolean value of SponsorDetails.
Sample code
updateAppStatusFlag.ApplicationId = applicationId;
var applicationStatuses =
await _applicationService
.UpdateApplicationStatusFlagsAsync<ApplicationStatusFlags>(updateAppStatusFlag);
var foo = "APPLICANTSPONSORDETAILS";
var type = applicationStatuses.GetType();
var test = type.
GetCustomAttributes(false)
.OfType<SectionFlagAttribute>()
.SingleOrDefault()
?.Name == foo;
Any ideas how to do this? I know I can use reflection but I've had problems getting it to work.
Thanks
In your example, you're getting the customattributes of the class instead of the properties.
Here is an example:
private object GetValueBySectionFlag(object obj, string flagName)
{
// get the type:
var objType = obj.GetType();
// iterate the properties
var prop = (from property in objType.GetProperties()
// iterate it's attributes
from attrib in property.GetCustomAttributes(typeof(SectionFlagAttribute), false).Cast<SectionFlagAttribute>()
// filter on the name
where attrib.Name == flagName
// select the propertyInfo
select property).FirstOrDefault();
// use the propertyinfo to get the instance->property value
return prop?.GetValue(obj);
}
Note: this will return only the first property which contains the SectionFlagAttribute with the right name. You could modify the method to return multiple values. (like a collection of propertyname/value)
Usage:
// a test instance.
var obj = new ApplicationStatusFlags { IceAttributeStatement = true };
// get the value by SectionFlag name
var iceAttributeStatement = GetValueBySectionFlag(obj, "APPLICANTSTATEMENT");
If the returned value is null then the flag is not found or the property's value is null.

mapping between an object and a dynamically created object after JSON deserialization

How do I do a mapping between an object created by instantiating a class and a dynamic object created by a JSON deserialization (JsonConvert) considering I don't know the dynamic object's fields? In other words, I'd like to update the dynamic object fields matching by name.
This is my example code:
string json = {\"NDG\":7803, \"NumberOfNights\":2, \"Nome\":\"Ago\", \"Cognome\":\"Mar\", \"CognomeNome\":\"\"};
string djson = ?? //I don't know the structure coming from a call as parameter but I know there are some json string identical fields
public class myVars
{
public string Userid { get; set; }
public string Nome { get; set; }
public string Cognome { get; set; }
public string CognomeNome { get; set; }
}
myVars object1 = JsonConvert.DeserializeObject<myVars>(json);
dynamic object2 = JObject.Parse(djson); // object2 contains a field named "CognomeNome"
myVars.CognomeNome = myVars.Cognome + myVarsNome;
MapObjects(object1 , object2);
string rjson = JsonConvert.SerializeObject(object2); //returns {"CognomeNome":""}
public static object MapObjects(object source, object target)
{
foreach (PropertyInfo sourceProp in source.GetType().GetProperties())
{
PropertyInfo targetProp = target.GetType().GetProperties().Where(p => p.Name == sourceProp.Name).FirstOrDefault();
if (targetProp != null && targetProp.GetType().Name == sourceProp.GetType().Name)
{
targetProp.SetValue(target, sourceProp.GetValue(source));
}
}
return target;
}
The simplest way is to use one of the existing automappers (Alternatives to AutoMapper)
For example, this:
https://github.com/agileobjects/AgileMapper/wiki/Performing-Updates sounds like it's what you are asking for.

Linq query - "Where" on List<T> Where reflected property Contains text/value

I would like to build a Function where user could search if certain property from list contains value
Let say we will have List, and Company will be defined as a class with properties like :
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
Now - Ideally I would like to have function with this parameters
List<Company> FilterCompanies(List<Company> unfilteredList, string fieldToQueryOn, string query)
{
// linq version what ideally would like to archeve
return unfilteredList.Where(x => x."fieldToQueryOn".ToString().ToLower().Contains(query.ToLower())).ToList();
}
and call :
var variable = FilterCompanies(NotNullFilledUnfilteredList, "CompanyCity", "New York")
I tried to follow the tutorial at learn.microsoft.com and it's easy, but I don't have clue how to extend that solution with reflection on Type and use it in an expression tree.
You can use Type.GetProperty to find a property by name using reflection, and then use GetValue to retrieve the value:
List<Company> FilterCompanies(List<Company> list, string propertyName, string query)
{
var pi = typeof(Company).GetProperty(propertyName);
query = query.ToLower();
return list
.Where(x => pi.GetValue(x).ToString().ToLower().Contains(query))
.ToList();
}
You should probably add some error handling though in case someone uses a property that is invalid. For example, you could do (pi?.GetValue(x) ?? string.Empty).ToString().ToLower()… to be on the safe side.
I’ve also moved the query.ToLower() out of the lambda expression to make sure it only runs once. You can also try other case-insensitive ways to check whether query is a substring of the value to avoid having to convert any string. Check out the question “Case insensitive 'Contains(string)'” for more information.
Btw. if you are generally interested in running dynamic queries, you should take a look at dynamic LINQ.
Generics and lambda:
namespace WhereTest
{
class Program
{
static void Main(string[] args)
{
var companies = new[] { new Company { Id = 1, Name = "abc" }, new Company { Id = 2, CompanyAddress1 = "abc" } };
foreach (var company in FilterCompanies(companies, "abc", x => x.Name, x => x.CompanyCity))
{
Console.WriteLine(company.Id);
}
}
static List<Company> FilterCompanies(IEnumerable<Company> unfilteredList, string query, params Func<Company, string>[] properties)
{
return unfilteredList.Where(x => properties.Any(c => c.Invoke(x) == query)).ToList();
}
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
}
Advantages: no reflection, strongly typed code.
You can use GetProperty combined with GetValue
List<Company> FilterCompanies(List<Company> unfilteredList, string fieldToQueryOn, string query)
{
return unfilteredList
.Where(x => x.GetType.GetProperty(fieldToQueryOn).GetValue(x)
.ToString().ToLower().Contains(query.ToLower())).ToList();
}
OR: property accessors using string (same as javascript obj[property])
You can modify your class:
public class Company
{
// just add this code block to all your classes that would need to access
// your function
public object this[string propertyName]
{
get{
Type myType = typeof(Company);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set{
Type myType = typeof(Company);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
and then you can change your function like this:
List<Company> FilterCompanies(List<Company> unfilteredList, string key, string query)
{
// linq version what ideally would like to archeve
return unfilteredList.Where(x => x[key].ToString().ToLower().Contains(query.ToLower())).ToList();
}
Check this Demo
NOTE:
In order for your function to work, you need to add this code to your classes:
public object this[string propertyName]
{
get{
Type myType = typeof(<YOUR CLASS HERE>);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set{
Type myType = typeof(<YOUR CLASS HERE>);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
Bonus: you can now retrieve values using myObject["someproperty"] and you can even set their values!

Passing more than 10 parameters between classes in C#?

I am a new to C#, I need a small help on how can I pass multiple parameters between the classes?
Below is a small example but my parameters will more than the 10. Is there another way to this?
public StreamStructure(String name, string id, string classname, int number)
{
this.name = name;
this.id = id;
this.classname = classname;
this.number = number;
}
List ------
List<abc> don = new List<abc>();
foreach (XmlElement abc_cdb in abc_cdbs)
{
abc.Name = abc_cdb.GetAttribute("NAME");
abc.Id = abc_cdb.GetAttribute("id");
abc.Clssname = abc_cdb.GetAttribute("classname");
abc.number = Convert.ToInt32(abc_cdb.GetAttribute("number"));
don.Add(abc);
}
I have used as suggested in ans but I am trying to create a list in C# my first record gets replaced with the 2nd one, since the fields in MyDTO are defined as public. Do you have any idea how to fix this?
Sure, use DTO's (data transfer objects). That is, create a class that has all the fields you want to send and use an instance of it as a parameter. Added bonus is that your method signature won't change even if you change your DTO class.
You are probably better off using C# Initializers or a Data Transfer Object than a large number of constructor parameters. Or combine the two.
public class MyDTO
{
String Name { get; set; }
String Id { get; set; }
String ClassName { get; set; }
int Number { get; set; }
}
var MyDTO = new MyDTO()
{
Name = Name,
Id = Id,
ClassName = ClassName,
Number = Number
}
var stream = new StreamStructure(MyDTO)
To create a list of these objects as in your example, create a new DTO within the loop body.
var don = new List<MyDTO>();
foreach (XmlElement abc_cdb in abc_cdbs)
{
var abc = new MyDTO()
{
Name = abc_cdb.GetAttribute("NAME");
Id = abc_cdb.GetAttribute("id");
ClassName = abc_cdb.GetAttribute("classname");
Number = Convert.ToInt32(abc_cdb.GetAttribute("number"));
};
don.Add( abc );
}
You could pass a domain object that represents the item you are manipulating.
public class Widget
{
public string Name {get;set;}
public int Id {get;set;}
public string ClassName {get;set;}
public int Number {get;set;}
}
var myWidget = new Widget();
myWidget.Name = "Blue Widget";
//etc
StreamStructure(myWidget);
You should write a new class that contains the properties you want to pass to the method, and change your method to include just that new class.
For your example, write a new class like this:
public class RequestObject
{
public string Name { get; set; }
public string ID { get; set; }
public string ClassName { get; set; }
public int Number { get; set; }
}
Then change your method like this:
public StreamStructure(RequestObject requestObject)
{
//DoStuff
}

Categories

Resources