So I have a horribly designed class that I can't change that has properties like this:
object.Color1
object.Color2
object.Color3
etc...
How can I iterate through those with a for loop. In other words, something like this:
for (int i = 0; i <= 40; i++)
{
string PropertyName = "Color" + i;
if (object.PropertyName != "")
{
// do something
}
}
Obviously this code wouldn't work but it gives you an idea of what I'm after. I have to do some processing on each property and I don't want to repeat my code 40 times. :) A loop would be perfect, I'm just not sure how to create the name of the property on the fly.
EDIT: Ok so I've tried the following code:
for (int i = 1; i <= 20; i++ )
{
var type = pendingProduct.GetType();
var colorProperty = type.GetProperty("Color" + i);
string colorValue = colorProperty.GetValue(type, null).ToString();
var colorSkuProperty = type.GetProperty("Color" + i + "SKU");
string colorSkuValue = colorSkuProperty.GetValue(type, null).ToString();
if (String.IsNullOrEmpty(colorValue)) continue;
ProductColor color = new ProductColor {Color = colorValue, ProductSizes = productSizes};
if (!String.IsNullOrEmpty(colorSkuValue)) color.SKU = colorSkuValue;
}
I'm getting an error "Object does not match target type" on this line:
string colorValue = colorProperty.GetValue(type, null).ToString();
Am I doing something wrong here?
You're looking for reflection:
PropertyInfo property = typeof(SomeType).GetProperty("Color" + i);
string value = (string)property.GetValue(obj, null);
Note that this will be slow.
If you do it many times, you can make it faster by caching Delegate.CreateDelegate(..., property.GetGetMethod()) in an array.
You can use reflection for that:
var type = myObject.GetType();
var property = type.GetProperty("Color1");
var value = property.GetValue(myObject, null));
This is how i do to help finding.
$abc = array(
'a' => 'world',
'b' => 'good',
);
$object = (object) $abc;
foreach($object as $k)
{
var_dump($object);
}
You can use reflection to get the property by name. In your example you can use:
var pi = obj.GetType().GetProperty(PropertyName);
var val = pi.GetValue(obj,null);
In order to obtain the value of the property which name is PropertyName. You should check for pi != null because if a requested property does not exists null is returned.
If the function you are writing is time critical, you should anyway pay attention that reflection has some performance drawbacks.
Have a look at InvokeMethod...
MSDN
Example at codeproject
You could try something along the lines of...
Type type = this.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo p in properties)
{
// Check property is the one you want
// and carry out your code...
}
Also, If you have access to the code I.E. you can change the internals but want to leave the public API intact you could just add the information to a private collection when the object is constructed. The collection could then be exposed by a public property for you to iterate over. A bit hacky but an alternative to using reflection.
Related
In C# I have multiple instantiations of a class "CItems"(see below). I retrieve a string at run-time of the instantiation I want to use(in this case to call a public method-"addPropertyToList"). I know I have to use reflection but I can't seem to get it right.
CItems me = new CItems();
CItems conversations = new CItems();
string whichCItem = "me"
properties = <whichCItem>.addPropertyToList(properties, "FirstName", "Ken");
I tried many things like:
var myobject = this;
string propertyname = "me";
PropertyInfo property = myobject.GetType().GetProperty(propertyname);
object value = property.GetValue(myobject, null);
But that resulted in:
Object reference not set to an instance of an object. Because property ends up null.
Thanks for any help and please be gentle. I really have no idea what I am doing and I may have used some wrong terminology.
A simple Dictionary<T, U> might work for you.
Consider an example:
CItems me = new CItems();
CItems conversations = new CItems();
...
var dic = new Dictionary<string, CITems>();
doc.Add("me", me);
doc.Add("conversations", conversations);
...
//find object
CITems result= null;
dic.TryGetValue(searchString, out result);
PropertyInfo property = myobject.GetType().GetProperty(propertyname);
This is the correct approach for tretrieving the property identified by propertyname. You already know the type it is declared on, so you just use
var propertyInfo = CItems.GetProperty(propertyname)
to retrieve the class property. What you now need to do is set that property on the identified instance, so that you can call
propertyInfo.SetValue(<instance>, value);
How are your instances identified? Surely you are not giving back the name of the variable in which the object pointer is stored?
Is something like the following achievable?
IEnumerable<CItems> myItems = new { new CItem("me"), new CItem("conversations") }
void somemethod(string instanceName, string propertyname)
{
var instance = myItems.FirstOrDefault(item => item.Name == instanceName);
if(instance == null) return;
var propertyInfo = CItems.GetProperty(propertyname);
propertyInfo.SetValue(instance, value);
}
This is the statement I used to set the value :
this.codeactivity.output.Value1
I am trying to change the numeric value alone to work dynamically.
string sValue = "1";
this.codeactivity.output.value+ svalue = "Worked";
I have given one more try as below.
PropertyInfo[] myPropertyInfo;
myPropertyInfo = this.CodeActivity.GetType().GetProperties();
this.CodeActivity.Output.
for (int i = 0; i < myPropertyInfo.Length; i++)
{
Console.WriteLine(myPropertyInfo[i].ToString());
}
Please help me with this. Thanks
**Question what i raised, here go the answer **
Statement One: this.codeactivity.output.Value1 here i am tried to change variable name(Value1) dynamically.
This is how i tried to change the value: Eval("this.codeactivity.output."&Value1&") it will work if i do it in VbScript. But here i am working with object oriented programming C#. Based on the comments to the question i started with C# Reflection concept, then i landed with the solution.
**Solution: **
string propertyValue = "Mohan"
string propertyName = "Value1"
Type type = this.codeactivity.output.GetType();
PropertyInfo propertyInfo = type.GetProperty(propertyName)//Get particular Property;
Type propertyType = propertyInfo.PropertyType; //get the property type
object propertyVal = Convert.ChangeType(propertyValue , propertyType);//based on type change value.
propertyInfo.SetValue(this.codeactivity.output, propertyVal, null);//Set the value of the property
Thanks
I'm using the following code to output values of properties:
string output = String.Empty;
string stringy = "stringy";
int inty = 4;
Foo spong = new Foo() {Name = "spong", NumberOfHams = 8};
foreach (PropertyInfo propertyInfo in stringy.GetType().GetProperties())
{
if (propertyInfo.CanRead) output += propertyInfo.GetValue(stringy, null);
}
If I run this code for the int, or for the Foo complex type, it works fine. But if I run it for the string (as shown), I get the following error on the line inside the foreach loop:
System.Reflection.TargetParameterCountException: Parameter count mismatch.
Does anyone know what this means and how to avoid it?
In case anyone asks 'why are you enumerating through the properties of a string', eventually I hope to create a generic class which will output the properties of any type passed to it (which might be a string...).
In this case, one of the string's properties is the indexer for returning the character at the specified location. Thus, when you try to GetValue, the method expects an index but doesn't receive one, causing the exception.
To check which properties require index you can call GetIndexParameters on the PropertyInfo object. It returns an array of ParameterInfo, but you can just check the length of that array (if there are no parameters, it will be zero)
System.String has an indexed property that returns the char in the specified location. An indexed property needs an argument (index in this case) therefore the exception.
Just as reference... if you want to avoid the TargetParameterCountException when reading properties values:
// Ask each childs to notify also, if any could (if possible)
foreach (PropertyInfo prop in options.GetType().GetProperties())
{
if (prop.CanRead) // Does the property has a "Get" accessor
{
if (prop.GetIndexParameters().Length == 0) // Ensure that the property does not requires any parameter
{
var notify = prop.GetValue(options) as INotifyPropertyChanged;
if (notify != null)
{
notify.PropertyChanged += options.OptionsBasePropertyChanged;
}
}
else
{
// Will get TargetParameterCountException if query:
// var notify = prop.GetValue(options) as INotifyPropertyChanged;
}
}
}
Hope it helps ;-)
I'm making a general nhibernate method that can determine, given an instantiated nhibernate mapped object at runtime, if that object is referenced by some other object in the 'database'.
This way, I'll be able to allow the user to delete objects if they are not referenced, and throw errors if they are (along with some info about how many things reference the object).
I ran into a snag though, when an entity is mapped cascade = all, I want them to be able to delete this thing even though other objects reference it.
So, I just need to know how I can use the Nhibernate.MetaData.IClassMetaData to determine if an 'entity type' or bag is cascade = all. I can't seem to find it after looking for a few minutes.
Any thoughts?
Thanks
Isaac
P.S. here is the method code (unfinished). IDomainObject just makes sure the passed object has an int ID property.
public int getReferenceCount<T>(T objectToCheck) where T : Interfaces.IDomainObject
{
Type objectType = typeof(T);
string className = objectType.Name;
IDictionary<string, NHibernate.Metadata.IClassMetadata> myDictionary = session.SessionFactory.GetAllClassMetadata();
int referenceCount = 0;
string fullClassName = objectType.FullName;
foreach (var thisClassPair in myDictionary)
{
NHibernate.Metadata.IClassMetadata thisClass = thisClassPair.Value;
for (int i = 0; i < thisClass.PropertyTypes.Length; i++)
{
string propertyName;
if (thisClass.PropertyTypes[i].Name == fullClassName)
{
if (thisClass.PropertyTypes[i] is NHibernate.Type.ManyToOneType || thisClass.PropertyTypes[i] is NHibernate.Type.OneToOneType)
{
propertyName = thisClass.PropertyNames[i];
List<object> results = this.HQLQuery<object>("from " + thisClassPair.Key + " as refClass where refClass."+propertyName+".id = '"+objectToCheck.ID+"'");
}
}
}
}
return 0;
}
var persister = (NHibernate.Persister.Entity.AbstractEntityPersister)thisClass;
var cascadeStyle = persister.GetCascadeStyle(i);
I have seen the reverse of this question quite a few times, but have not seen how to do what I would like.
Suppose I have the following code:
var myNewData = from t in someOtherData
select new
{
fieldName = t.Whatever,
fieldName2 = t.SomeOtherWhatever
};
If I wish to data bind to this class, my column definition would have to include hard-coded strings like "fieldName" and "fieldName2".
Is there any way to call reflection or something else so that I can do something equivelent to the code below (I know the code below is not valid, but am looking for a valid solution).
string columnName = GetPropertyName(myNewData[0].fieldName);
My goal is that if the variable name changes on the anonymous class, a compile-time error would come up until all references were fixed, unlike the current data binding which relies on strings that are not checked until runtime.
Any help would be appreciated.
string columnName = GetPropertyName(() => myNewData[0].fieldName);
// ...
public static string GetPropertyName<T>(Expression<Func<T>> expr)
{
// error checking etc removed for brevity
MemberExpression body = (MemberExpression)expr.Body;
return body.Member.Name;
}
You get your property names like this:
using System.Reflection;
var myNewData = from t in someOtherData
select new
{
fieldName = t.Whatever,
fieldName2 = t.SomeOtherWhatever
};
foreach (PropertyInfo pinfo in myNewData.FirstOrDefault()
.GetType().GetProperties())
{
string name = pinfo.Name;
}
// or if you need all strings in a list just use:
List<string> propertyNames = myNewData.FirstOrDefault()
.GetType().GetProperties().Select(x => x.Name).ToList();