C# how Set property dynamically by string? - c#

First of all I'm not into programming, but could figure out the basic concept
up to my needs.
In the below code, I want to set the property by name "Gold" in something like:
_cotreport.Contract = COTReportHelper.ContractType."Blabalbal"
protected override void OnBarUpdate()
{
COTReport _cotreport = COTReport(Input);
_cotreport.Contract=COTReportHelper.ContractType.Gold;
_cotreport.OpenInterestDisplay=COTReportHelper.OpenInterestDisplayType.NetPosition;
double index = _cotreport.Commercial[0];
OwnSMA.Set(index);
}
I tried below code, but the system says: "
Object reference not set to an instance of an object"
Please help!
System.Reflection.PropertyInfo PropertyInfo = _cotreport.GetType().GetProperty("ContractType");
PropertyInfo.SetValue(_cotreport.Contract,"Gold",null);
PropertyInfo.SetValue(_cotreport.Contract,Convert.ChangeType("Gold",PropertyInfo.PropertyType),null);

You're trying to set get a property named "ContractType" on _cotreport and set it's value with on _cotreport.Contract. That's not going to work for two reasons.
The property name (from what I can tell in your code) is Contract not ContractType.
You need to set the value on _cotreport.
Try this instead
System.Reflection.PropertyInfo property = _cotreport.GetType().GetProperty("Contract");
property.SetValue(_cotreport, COTReportHelper.ContractType.Gold, new object[0]);
If you want to set the enum value by name, that's a separate issue. Try this
var enumValue = Enum.Parse(typeof(COTReportHelper.ContractType), "Gold");
property.SetValue(_cotreport, enumValue, new object[0]);

PropertyInfocould be null, and may not be if you used the property name: Contract. And you should be able to specify COTReportHelper.ContractType.Gold as the value directly. And you specify the property as the instance to be modified, but the PropertyInfo represents that, you should specify the owning instance on which the property value should be set.
Something like this:
System.Reflection.PropertyInfo PropertyInfo = _cotreport.GetType().GetProperty("Contract");
PropertyInfo.SetValue(_cotreport, COTReportHelper.ContractType.Gold, null);

This method sets value of property of any object and returns true if assignment was successfull:
public static Boolean TrySettingPropertyValue(Object target, String property, String value)
{
if (target == null)
return false;
try
{
var prop = target.GetType().GetProperty(property, DefaultBindingFlags);
if (prop == null)
return false;
if (value == null)
prop.SetValue(target,null,null);
var convertedValue = Convert.ChangeType(value, prop.PropertyType);
prop.SetValue(target,convertedValue,null);
return true;
}
catch
{
return false;
}
}

Related

How to search if an object has a property with a value C#

I would like to create a function where I can pass in an arbitrary object and check to see if it has a specific property with a specific value. Im attempting to do this using reflection, but reflection still confuses me a little bit. I was hoping that someone might be able to point me in the right direction.
here is the code that im trying but obviously it doesnt work:
public static bool PropertyHasValue(object obj, string propertyName, string propertyValue)
{
try
{
if(obj.GetType().GetProperty(propertyName,BindingFlags.Instance).GetValue(obj, null).ToString() == propertyValue)
{
Debug.Log (obj.GetType().FullName + "Has the Value" + propertyValue);
return true;
}
Debug.Log ("No property with this value");
return false;
}
catch
{
Debug.Log ("This object doesnt have this property");
return false;
}
}
You will want to specify more BindingFlags in the Type.GetProperty method call. You do this with a | character and the other flags, such as BindingFlags.Public. Other issues are not checking for null obj parameter or null result from your PropertyInfo.GetValue call.
To be more explicit in your method, you could write it like this and collapse down where you see fit.
public static bool PropertyHasValue(object obj, string propertyName, string propertyValue)
{
try
{
if(obj != null)
{
PropertyInfo prop = obj.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
if(prop != null)
{
object val = prop.GetValue(obj,null);
string sVal = Convert.ToString(val);
if(sVal == propertyValue)
{
Debug.Log (obj.GetType().FullName + "Has the Value" + propertyValue);
return true;
}
}
}
Debug.Log ("No property with this value");
return false;
}
catch
{
Debug.Log ("An error occurred.");
return false;
}
}
In my opinion you should accept propertyValue as an object and compare the objects equally, but that would exhibit a different behavior than your original sample.
Its too late to answer this question here. But I was searching for the same problem and solved it in a cleaner way with LINQ and Reflection. So if you are open to LINQ. You can get it like this.
String propertyValue = "Value_to_be_compared";
Bool Flag = YourObject.GetType().GetProperties().Any(t => t.GetValue(objEmailGUID, null).ToString().Contains(propertyValue));
if(Flag)
{
//spread love if true
}
Code will check if any of the property of you object Contains the Value_to_be_compared
If you want to match exact value then you can go for:
Bool Flag = YourObject.GetType().GetProperties().Any(t => t.GetValue(objEmailGUID, null).ToString() == propertyValue);
When retrieving members, in addition to specifying instance/static you must specify Public/NonPublic:
For example, to retrieve public properties you would use:
GetProperty(propertyName,BindingFlags.Instance | BindingFlags.Public)
To retrieve all properties you must retrive both Public and NonPublic.
You should take a look at msdn and read up about binding flags. In specific:
You must specify Instance or Static along with Public or NonPublic or no members will be returned.

How can I get the name and value of a property using reflection?

I have this code and I am using it to raise the PropertyChanged event without passing the name of property to the function.
private void RaisePropertyChanged<TValue>(Expression<Func<TValue>> propertySelector)
{
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression != null)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(memberExpression.Member.Name));
}
}
}
and I am calling it in this way:
this.RaisePropertyChanged(() => this.IsReady);
Which will raise the PropertyChanged event for the IsReady property. I like the idea as writing code in this way will help to change the name of the property very easily.
Now I want to use the same technique to pass the name and value of a property to a method. Is there any way that I can do this?
You already have it:
string name = memberExpression.Member.Name;
TValue value = propertySelector.Compile()();
An alternative would be to look at the member.MemberType, cast to PropertyInfo or FieldInfo respectively:
var member = memberExpression.Member;
string name = member.Name;
object value;
switch(member.MemberType) {
case MemberTypes.Field:
value = ((FieldInfo)member).GetValue(this);
break;
case MemberTypes.Property:
value = ((PropertyInfo)member).GetValue(this, null);
break;
default:
throw new NotSupportedException(member.MemberType.ToString());
}
However, a simpler approach is... to simply pass the name and value to the method:
Foo("IsReady", IsReady);
It depends a bit on how efficient it needs to be, though (reflection/expression does add an overhead - whether that is significant depends on the context).
For getting the name you can use memberExpression.Member.Name and for getting the value you could use this.GetType().GetProperty (memberExpression.Member.Name).GetGetMethod().Invoke (this, null).

How to i return the value of a property if i dont know the propertyname at run-time?

And let's assume for simplicity that the value of the property needs to always be returned as a string.
public string GetTheValueOfTheProperty(PropertyInfo propertyInfo,Object myObject){
string propname = propertyInfo.Name;
if (propName == "IsSelected"){
return myObject.IsSelected.ToString();
}
//...
}
This works, but it doesn't work if I don't know the name of the property. How would I do that in that scenario ?
http://msdn.microsoft.com/en-us/library/system.reflection.propertyinfo.getvalue.aspx
You can call propertyInfo.GetValue(myObject, null);.
You can convert to a string with ToString(), but you should check for null values first - otherwise you'll get a NullReferenceException.
The PropertyInfo object lets you invoke the property on the object:
object value = propertyInfo.GetGetMethod().Invoke(myObject, new object[] { });

How to set the value of a property if it is null?

I am trying to write my first WCF Service. Right now I just want to take a bunch of properties of an object and write them to SQL Server.
Not all the property values will always be set so I would like to receive the object on the service side, loop through all the properties on the object and if there are any of a string datatype that are not set, set the value to "?".
All the properties of object are defined of type string
I am trying the following code found here but get the error "Object does not match target type." on the line indicated below
foreach (PropertyInfo pInfo in typeof(item).GetProperties())
{
if (pInfo.PropertyType == typeof(String))
{
if (pInfo.GetValue(this, null) == "")
//The above line results in "Object does not match target type."
{
pInfo.SetValue(this, "?", null);
}
}
}
How should I be checking if a property of string type on an object has not been set?
The value returned from PropertyInfo.GetValue is object. However, since you know the value is a string (because you checked in the line above) you can tell the compiler "I know this is a string" by doing a cast:
if (pInfo.PropertyType == typeof(String))
{
string value = (string) pInfo.GetValue(this, null);
if (value == "")
{
Also, I would add an extra null check in there, just in case the value is null or empty. Luckily, there's the string.IsNullOrEmpty method for that:
if (pInfo.PropertyType == typeof(String))
{
string value = (string) pInfo.GetValue(this, null);
if (string.IsNullOrEmpty(value))
{

Reflection & Parameters in C#

I'm writing an application that runs "things" to a schedule.
Idea being that the database contains assembly, method information and also the parameter values. The timer will come along, reflect the method to be run, add the parameters and then execute the method.
Everything is fine except for the parameters.
So, lets say the method accepts an ENUM of CustomerType where CustomerType has two values of CustomerType.Master and CustomerType.Associate.
EDIT
I don't know the type of parameter that will be getting passed in. ENUM used as an example
END OF EDIT
We want to run Method "X" and pass in parameter "CustomerType.Master". In the database, there will be a varchar entry of "CustomerType.Master".
How do I convert the string "CustomerType.Master" into a type of CustomerType with a value of "Master" generically?
Thanks in advance,
Jim
OK, the scope of the question shifted but my original observation and objection to some other solutions still stands.
I think you don't/can't want to use 'generics' here. You don't know the type ahead of time, and since you will need to create the type, there is no need to use a generic implementation because MethodBase.Invoke takes an array of Object.
This code assumes you are instantiating the target from database field. If not just adjust accordingly.
Of course this is not all encompassing and has no useful exception handling, but it will allow you to dynamically execute arbitrary methods on an arbitrary type with arbitrary parameters values all coming from string values in a row.
NOTE: there are many many many scenarios in which this simple executor will not work. You will need to ensure that you engineer your dynamic methods to cooperate with whatever strategy you do end up deciding to use.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using NUnit.Framework;
namespace DynamicMethodInvocation
{
[TestFixture]
public class Tests
{
[Test]
public void Test()
{
// from your database
string assemblyQualifiedTypeName = "DynamicMethodInvocation.TestType, DynamicMethodInvocation";
string methodName = "DoSomething";
// this is how you would get the strings to put in your database
string enumString = Executor.ConvertToString(typeof(AttributeTargets), AttributeTargets.Assembly);
string colorString = Executor.ConvertToString(typeof(Color), Color.Red);
string stringString = "Hmm... String?";
object result = Executor.ExecuteMethod(assemblyQualifiedTypeName, methodName,
new[] { enumString, colorString, stringString });
Assert.IsInstanceOf<bool>(result);
Assert.IsTrue((bool)result);
}
}
public class TestType
{
public bool DoSomething(AttributeTargets #enum, Color color, string #string)
{
return true;
}
}
public class Executor
{
public static object ExecuteMethod(string assemblyQualifiedTypeName, string methodName,
string[] parameterValueStrings)
{
Type targetType = Type.GetType(assemblyQualifiedTypeName);
MethodBase method = targetType.GetMethod(methodName);
ParameterInfo[] pInfo = method.GetParameters();
var parameterValues = new object[parameterValueStrings.Length];
for (int i = 0; i < pInfo.Length; i++)
{
parameterValues[i] = ConvertFromString(pInfo[i].ParameterType, parameterValueStrings[i]);
}
// assumes you are instantiating the target from db and that it has a parameterless constructor
// otherwise, if the target is already known to you and instantiated, just use it...
return method.Invoke(Activator.CreateInstance(targetType), parameterValues);
}
public static string ConvertToString(Type type, object val)
{
if (val is string)
{
return (string) val;
}
TypeConverter tc = TypeDescriptor.GetConverter(type);
if (tc == null)
{
throw new Exception(type.Name + " is not convertable to string");
}
return tc.ConvertToString(null, CultureInfo.InvariantCulture, val);
}
public static object ConvertFromString(Type type, string val)
{
TypeConverter tc = TypeDescriptor.GetConverter(type);
if (tc == null)
{
throw new Exception(type.Name + " is not convertable.");
}
if (!tc.IsValid(val))
{
throw new Exception(type.Name + " is not convertable from " + val);
}
return tc.ConvertFrom(null, CultureInfo.InvariantCulture, val);
}
}
}
I would think you have 2 major options:
Store the type name along with the parameter value and use that to cast things using Type.GetType(string) to resolve the type in question.
Standardize all the methods to be called this way to accept an array of strings, and expect the methods to do any necessary casting.
I know you've stated that you're not doing option 1, but it would help things from the standpoint of calling the functions.
Option 2 is the far more 'generic' way to handle the situation, assuming all values can be represented by and cast/converted from strings to the appropriate type. Of course, that only helps if you actually have control over the definition of the methods being called.
Below is a useful extension method I use in .NET 3.5.
With this extension method available, your code could look like this:
var valueInDb = GetStringFromDb().Replace("CustomerType.", string.Empty);
var value = valueInDb.ToEnum(CustomerType.Associate);
By supplying the default value in the parameter, the compiler will know which Enum you want your string to be turned into. It will try to find your text in the Enum. If it doesn't it will return the default value.
Here is the extension method: (this version also does partial matches, so even "M" would work nicely!)
public static T ToEnum<T>(this string input, T defaultValue)
{
var enumType = typeof (T);
if (!enumType.IsEnum)
{
throw new ArgumentException(enumType + " is not an enumeration.");
}
// abort if no value given
if (string.IsNullOrEmpty(input))
{
return defaultValue;
}
// see if the text is valid for this enumeration (case sensitive)
var names = Enum.GetNames(enumType);
if (Array.IndexOf(names, input) != -1)
{
// case insensitive...
return (T) Enum.Parse(enumType, input, true);
}
// do partial matching...
var match = names.Where(name => name.StartsWith(input, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
if(match != null)
{
return (T) Enum.Parse(enumType, match);
}
// didn't find one
return defaultValue;
}
I still don't fully understand your question... however, you say "Everything is fine except for the parameters."
I'll assume "CustomerType" the name of a property on your object, and "Master" is the string value you want to put in that property.
Here is (another) extension method that may help.
Once you have your new object and the value and property name from the database field, you could use this:
// string newValue = "Master";
// string propertyName = "CustomerType";
myNewObject.SetPropertyValue(propertyName, newValue)
Method:
/// <summary>Set the value of this property, as an object.</summary>
public static void SetPropertyValue(this object obj,
string propertyName,
object objValue)
{
const BindingFlags attr = BindingFlags.Public | BindingFlags.Instance;
var type = obj.GetType();
var property = type.GetProperty(propertyName, attr);
if(property == null) return;
var propertyType = property.PropertyType;
if (propertyType.IsValueType && objValue == null)
{
// This works for most value types, but not custom ones
objValue = 0;
}
// need to change some types... e.g. value may come in as a string...
var realValue = Convert.ChangeType(objValue, propertyType);
property.SetValue(obj, realValue, null);
}
If you are using .NET 4 you can do the following.
var result = default(CustomerType);
if (!Enum.TryParse("Master", out result))
{
// handle error
}

Categories