I have a series of methods to write, but I think there is some commonality (well, I know there is). The method I'd like to see will take two things, an object and... well, I'm not so sure about the second one, but probably a string.
The object should be generic, although it can only be from a set list (in this case, that commonality seems to be that they inherit from both INotifyPropertyChanging and INotifyPropertyChanged interfaces).
The string should be the name of a property within the generic object. It should be checked to see if that property exists within that object before being put into use (it would be used as a way to compare the objects by that given property).
So I guess the process would be... generic object gets passed into method (along with property name string). A check to see if the object contains the property. If it does, continue and somehow have access to 'object.PropertyName' where 'PropertyName' was the supplied string.
I don't know if it's easy or possible or even wise, but I know that it would save me some time.
Thanks in advance for any advice you might be able to offer with this.
Edit: Thanks for the all the replies so far guys. Let me clarify some things:
Clarification of 'access'
When I said, "... and somehow have access to 'object.PropertyName'", what I meant was that the method should be able to use that property name as if it were just a property of that object. So, let's say the string passed in was "ClientName", there would be the ability to read (possibly write, although at the moment I don't think so as it's just a check) object.ClientName, if it was determined that existed.
What I'm trying to do
I have a WCF service which accesses an SQL database using Linq. The objects I spoke of are entities, generated from the program SQLMetal.exe, so my objects are things like 'Client', 'User' and this sort of thing. I wrote a method which took a List of entities. This method added only those entities which did not exist within the collection (some could have been duplicates). It figured out which ones were duplicates by checking a property within the entity (which corresponds to data in a column of the database). It's that property which I figured might be variable.
It sounds like you don't really want to check if it's a certain type, and if that is so then you don't have to and its actually easier not to check the type. This shows how to check if the property exists and if it is readable and writeable and shows how to use it after it's found:
private void Form1_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
PropertyInfo info = GetProperty(sb, "Capacity");
//To get the value of the property, call GetValue on the PropertyInfo with the object and null parameters:
info.GetValue(sb, null);
//To set the value of the property, call SetValue on the PropertyInfo with the object, value, and null parameters:
info.SetValue(sb, 20, null);
}
private PropertyInfo GetProperty(object obj, string property)
{
PropertyInfo info = obj.GetType().GetProperty(property);
if (info != null && info.CanRead && info.CanWrite)
return info;
return null;
}
I think only indexer properties can take parameters in C#. And I believe if you wrote properties in VB that take parameters and tried to reference that assembly in C# they would show up as methods instead of properties.
You could also write a function like this that would take 2 objects and a string for a property name and return the result of those properties matching:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info1 = obj1.GetType().GetProperty(propertyName);
PropertyInfo info2 = obj2.GetType().GetProperty(propertyName);
if (info1 != null && info1.CanRead && info2 != null && info2.CanRead)
return info1.GetValue(obj1, null).ToString() == info2.GetValue(obj2, null).ToString();
return false;
}
Comparing the values of the properties might be tricky because it would compare them as objects and who knows how equality will be handled for them. But converting the values to strings should work for you in this case.
If you know the 2 objects are the same type then you can simplify it:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info = obj1.GetType().GetProperty(propertyName);
if (info != null && info.CanRead)
return info.GetValue(obj1, null).ToString() == info.GetValue(obj2, null).ToString();
return false;
}
I think you're looking for something like:
public void SomeMethod<T>(T object, string propName)
where T : INotifyPropertyChanging, INotifyPropertyChanged
(
var type = typeof(T);
var property = type.GetProperty(propName);
if(property == null)
throw new ArgumentException("Property doesn't exist", "propName");
var value = property.GetValue(object, null);
)
Related
EDIT: Updated example to what I'm actually doing.
EDIT 2: The why:
My class "takes hold" of a property setter (or method, anonymous or not) and "controls" it for a period of time. The user could try and attach another instance of my class and attach that to a property that is already "controlled." I need a way to detect these conflicts reliably. I could forego the () => { property } method but that requires the user to wrap the target property in a method and, if he/she wants conflict detection, to pass in the object containing the property. Doing it that way introduces higher risk of bugs as they may type in the wrong object and the class wouldn't have any means to check for them.
I am unable to utilize the Lambda Compile() because I am targeting AOT in addition to JIT.
I have a method that takes an
Expression<Func<T>>
as an argument. The Expression always evaluates to a property with a setter of Type T.
private static TargetInfo GetTargetInfo<T>(Expression<Func<T>> _propertyExpression, out Action<T> _setter)
{
//Get Property info
var propInfo = ((MemberExpression)_propertyExpression.Body).Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException("_propertyExpression must be a property.");
var declType = propInfo.DeclaringType;
var methodInfo = propInfo.GetSetMethod(true) ?? declType.GetProperty(propInfo.Name).GetSetMethod(true);
if (methodInfo == null)
throw new Exception("Could not create setter from property '" + _propertyExpression + "'");
var isStaticProp = methodInfo.IsStatic;
//Get Target Object
object targetObject = null;
var memberExp = _propertyExpression.Body as MemberExpression;
var bodyExp = memberExp.Expression;
if (bodyExp != null)
// PROBLEM LINE BELOW - Can't use Compile() *********************************
targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();
// PROBLEM LINE ABOVE *******************************************************
else if (isStaticProp)
targetObject = memberExp.Member.DeclaringType;
else
throw new Exception("Could not determine target object. Use Action<T> overload. (no conflict detection)");
//Cache setter of property
if (isStaticProp)
_setter = (Action<T>) Delegate.CreateDelegate(typeof (Action<T>), methodInfo);
else
_setter = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), targetObject, methodInfo);
return new TargetInfo(methodInfo, targetObject);
}
The expression (_propertyExpression) is always of a property. And the property always has a setter.
I need to extract the property's setter as Action (which I can do
no problem)
I also need the instance of the object containing this
property without using Compile() as it is not available on some of
the target platforms I am targeting.
The reason I need the instance is to determine whether or not another object instance of my class is currently utilizing that property SETTER on THAT object. (No Threading, just usage over a span of time) I store the object Instance and property setter info together as a key, if two keys that are equal that exist then there is a conflict and it is handled based on the user's configuration settings of my class.
I am able to get the object instance for simple expressions like:
() => MyProperty
or
() => MyObjectInst.PropertyFoo
or
() => MyStaticClass.PropertyFooBar
No Sweat!
But what if the user does this:
//Need instance of 'someObject' here.
() => SomeArray[idx].someObject.propertyA
or blow my top:
//Need instance of 'someField[4]' here
() => SomeStaticClass.somePropertyList[5].SomeDictionary[objKey].SomeProperty.someFieldArray[4].propertyB
AAAK!
I've been looking at this for a while and I BELIEVE that I need to traverse the tree BACK to the base object (ConstantExpression) then start evaluating back UP the tree using the info collected walking to the front. Given the examples above I decided that I need "bigger guns".
Is there an easier way to get the property's caller's instance other than completely walking the tree WITHOUT using Compile()? Please explain if so!
If not 1. If anyone could point me in the right direction on how to traverse the tree and handle stuff like the above. That would be great. I'm not finding a whole lot of info on traversing Expression Trees, expression types, etc. Even a reference to a recommended book specific to the subject would be helpful.
sigh Should I just give up and force the user to use simple expressions.
ie. Do not allow the user to type in lengthy property access lines.
Clarification:
The setter is being cached for use by a mechanism class "FOO" that will be setting this value an UNKNOWN range of values of type T over some defined period of time. The object instance is cached and used as a key to detect the case that another instance of FOO tries to attach and set values to the same property on that same object. The object instance is used to detect these conflicts and also to keep track of all of the "FOO"s attached to any particular object. The user can attach multiple "FOO"s to the same object, to different properties. In the case that the user attaches an instance of FOO to a property on an object that already has a FOO attached for that property, a conflict event occurs. FOO can be configured on how to handle when that happens.
Here's the problems with your suggested approaches:
Is there an easier way to get the property's caller's instance other
than completely walking the tree WITHOUT using Compile()? Please
explain if so!
Short answer, no. Expressions are meant to be compiled. Either into .NET Funcs/Actions or some other platform (LINQ-to-Entities essentially compiles them into SQL). If you don't want to compile it, you're probably using the wrong tool.
If not 1. If anyone could point me in the right direction on how to
traverse the tree and handle stuff like the above. That would be
great. I'm not finding a whole lot of info on traversing Expression
Trees, expression types, etc. Even a reference to a recommended book
specific to the subject would be helpful.
The best way to traverse an Expression tree is by inheriting from ExpressionVisitor. A good blog to start with would be Matt Warren's blog http://blogs.msdn.com/b/mattwar/, read the series on implementing IQueryable. But no, it's not easy.
One could (theoretically) inherit from ExpressionVisitor to walk down/up the chain to the original instance. But you would then have to walk back up/down the chain somehow, and the easiest way to do that would be by compiling the child Expressions. You could, theoretically, use Reflection to walk back, as your answer tries, but I hope you're distinctly getting the impression you have chosen the wrong tool if your No-Compiling stance is iron-clad.
sigh Should I just give up and force the user to use simple expressions.
You haven't outlined the benefits/drawbacks of this.
I have confirmed that the below works on for MONO -> iOS... At least with the basics and arrays. Haven't been able to get the Dictionary/List rolling. It seems AOT doesn't like MethodInfo.Invoke.
EDIT:
I found this answer on MSDN:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/af305a45-36e4-4607-9190-f1b33a0bea57/get-class-instance-from-lambda-expression
It traverses the Expression tree, evaluating each part of the tree as necessary and finally returns the containing object of the property specified.
Put in this (along with adding the method code below in):
targetObject = GetContainer(_propertyExpression);
instead of this:
targetObject = Expression.Lambda<Func<object>>(bodyExp).Compile()();
in the code above.
I have yet to do full testing on it on other platforms and I'm sure I'll run into other cases where I need to add more cases but this might be enough to help someone else and enough to keep me going and I'll try and keep this updated as I run into more:
public static object GetContainer<T>(Expression<Func<T>> propertyLambdaExpression)
{
return Evaluate((propertyLambdaExpression.Body as MemberExpression).Expression);
}
public static object Evaluate(Expression e)
{
switch (e.NodeType)
{
case ExpressionType.Constant:
return (e as ConstantExpression).Value;
case ExpressionType.MemberAccess:
{
var propertyExpression = e as MemberExpression;
var field = propertyExpression.Member as FieldInfo;
var property = propertyExpression.Member as PropertyInfo;
var container = propertyExpression.Expression == null ? null : Evaluate(propertyExpression.Expression);
if (field != null)
return field.GetValue(container);
else if (property != null)
return property.GetValue(container, null);
else
return null;
}
case ExpressionType.ArrayIndex: //Arrays
{
var arrayIndex = e as BinaryExpression;
var idx = (int)Evaluate(arrayIndex.Right);
var array = (object[])Evaluate(arrayIndex.Left);
return array[idx];
}
case ExpressionType.Call: //Generic Lists and Dictionaries
{
var call = e as MethodCallExpression;
var callingObj = Evaluate(call.Object);
object[] args = new object[call.Arguments.Count];
for (var idx = 0; idx < call.Arguments.Count; ++idx)
args[idx] = Evaluate(call.Arguments[idx]);
return call.Method.Invoke(callingObj, args);
}
default:
return null;
}
}
Recently, I ran into a problem of comparing 2 objects of the same class in C#. I need to know which fields/properties are changed.
Here is the example:
SampleClass
{
string sampleField1;
int sampleField2;
CustomClass sampleField3;
}
And I have 2 SampleClass object, object1 and object2, for example.
These 2 objects have some different field value.
Can anyone know the best approach to get which fields are different?
And how to get the (string) names of that different fields/properties?
I heard of Reflection in .Net. Is that the best approach in this situation?
And if we didn't have the CustomClass field? (I just make this field for a more general approach, that field does not exist in my case)
If you want Generic way to get all changed properties
you can use this method (and it is using reflection ^_^ )
public List<string> GetChangedProperties(object obj1, object obj2)
{
List<string> result = new List<string>();
if(obj1 == null || obj2 == null )
// just return empty result
return result;
if (obj1.GetType() != obj2.GetType())
throw new InvalidOperationException("Two objects should be from the same type");
Type objectType = obj1.GetType();
// check if the objects are primitive types
if (objectType.IsPrimitive || objectType == typeof(Decimal) || objectType == typeof(String) )
{
// here we shouldn't get properties because its just primitive :)
if (!object.Equals(obj1, obj2))
result.Add("Value");
return result;
}
var properties = objectType.GetProperties();
foreach (var property in properties)
{
if (!object.Equals(property.GetValue(obj1), property.GetValue(obj2)))
{
result.Add(property.Name);
}
}
return result;
}
Please note that this method only gets Primitive type properties that have changed and reference type properties that refer to the same instance
EDIT: Added validation in case if obj1 or obj2 is primitive type (int,string ... ) because I tried to pass string object and it will give an error
also fixed bug of checking whether the two values are equal
A slight modification of another answer posted here, but this one works with properties that are not string types, doesn't use an internal list and does automatic some preliminary type checking as it's generic:
public IEnumerable<string> ChangedFields<T>(T first, T second)
{
if (obj1.GetType() != obj2.GetType())
throw new ArgumentOutOfRangeException("Objects should be of the same type");
var properties = first
.GetType()
.GetProperties();
foreach (var property in properties)
{
if(!object.Equals(property.GetValue(first), property.GetValue(second)))
{
yield return property.Name;
}
}
}
If you need to compare two objects as part of your business logic reflection is the way to go, unless of course you can write comparator classes for each type.
If you want to compare two objects at run time during debugging, there is a neat plugin called Oz Code that can do that for you, something like this:
I think I'm having boxing issues
foreach(var p in item.GetType().GetProperties().
Where(p => p.GetValue(original, null) is ValueType))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (!originalValue.Equals(modifiedValue))
kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
originalValue is never equal to modifiedValue, Im guessing it's because they are boxed inside Object. But how do I fix it?
It is not a boxing issue. Equals is a virtual method, which the boxed value types override just fine.
However, I am not sure what the issue is. Could it be that there aren’t actually any matching properties? Remember that GetProperties() without any parameters will only return public properties. If the properties you need are private, you need to add some BindingFlags:
GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
(I’m assuming here that you don’t want static properties.)
Are you also sure that it is actually properties that you are after and not fields? Remember that if you declare something as
public string Name;
then it’s a field, whereas
public string Name { get; set; }
is a property. If it’s actually fields you need, you need to use GetFields() instead of GetProperties() with the same binding flags.
Linq is a great tool, but I'm not sure why you're using it here. You're actually causing the set of properties to get iterated twice, which is very expensive. I'd write the code without Linq. Also, there's no need to get the value more than once, which is again very expensive. Give this code a try. It avoids the flaws I pointed out and was comparing correctly when I made and tested a dummy class with it:
foreach(PropertyInfo p in item.GetType().GetProperties())
{
if (p.PropertyType.BaseType == typeof(ValueType) || p.PropertyType == typeof(string))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (originalValue != modifiedValue) kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
}
Also, note that strings are not a ValueType although they do implement a value comparison.
From MSDN: Object.Equals :
The default implementation of Equals supports reference equality for
reference types, and bitwise equality for value types. Reference
equality means the object references that are compared refer to the
same object. Bitwise equality means the objects that are compared have
the same binary representation.
That means that in your case this 2 objects (if they are reference types) are never point to the same instance.
There is no an easy way to resolve this in so generic way as you would like to do.
But you can implement (just an example) an IComparable on those types you gonna to compare, and after in this iteration check if the type of the value rturned implements that interface, so cast and call it's implemented IComparable.CompareTo method.
You can check if the object implements specified interfacce, in this current case IComparable, you can do something like this:
originalValue .GetType().GetInterfaces().Any(x =>
x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IComparable))
Hope this helps.
Let's say I have an object of Type User that looks like this:
User {
Name = "Bob",
Email = "Bob#gmail.com",
Class = NULL
}
Can anyone think of a way to take that object and create an object like this:
User {
Name = "Bob",
Email = "Bob#gmail.com"
}
Using entirely generic code? Meaning, I don't want to hard code anything to do with the Type, or the Properties because this code would need to be applied to every Entity on my site. (the "User" type is an Entity by the way, so use that if it helps you code this better).
I'm just trying to come up with a solution to a problem I have and I BELIEVE that Stub Entities may fix the problem, but I need to do it without hard coding any Types or Properties.
Use reflection to achieve this:
public void CopyValues<TSource, TTarget>(TSource source, TTarget target)
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
foreach (var property in sourceProperties)
{
var targetProperty = typeof(TTarget).GetProperty(property.Name);
if (targetProperty != null && targetProperty.CanWrite && targetProperty.PropertyType.IsAssignableFrom(property.PropertyType))
{
var value = property.GetValue(source, null);
targetProperty.SetValue(target, value, null);
}
}
}
Generics are not gonna help you for this case. There might be some option in the Entity Framework but i am not really known with that.
It would however be possible using Reflection. You could try something like this:
public static void CopyProperties(object a, object b)
{
if (a.GetType() != b.GetType())
throw new ArgumentException("Types of object a and b should be the same", "b")
foreach (PropertyInfo property in a.GetType().GetProperties())
{
if (!property.CanRead || !property.CanWrite || (property.GetIndexParameters().Length > 0))
continue;
property.SetValue(b, property.GetValue(a, null), null);
}
}
Keep in mind tough that this requires all the properties you want to copy to have both a public setter and getter. Also there is the difference between "deep copy" vs "shallow copy" wich means if sub-objects are also copied or only referenced. This example will only reference them so it would be a "shallow copy"
This looks like a problem for reflection rather than generics (although generics can be used as a sneaky way of caching the strategy for reflection). Unless I misread it, you want to create a new instance and copy most of the members... Which reflection is good at, albeit relatively slow. You can improve the speed by using meta-programming; on the first run (per-type) generate an optimised version, perhaps using DynamicMethod or Expression, and store a typed delegate from that. Then just use the delegate.
I'm trying to use reflection to set properties on some OpenXML types (e.g. Justification). Assigning a value by enumerating all possibilities is straight-forward:
// attr is an XmlAttribute, so .Name and .Value are Strings
if (attr.Name == "Val")
{
if (element is Justification)
{
((Justification)element).Val = (JustificationValues)Enum.Parse(typeof(JustificationValues), attr.Value);
return;
}
else
{
// test for dozens of other types, such as TabStop
}
}
What makes this difficult to do via reflection is:
1) The type of the Val property is EnumValue<T>, so I don't know how to extract the type to pass as the first argument to Enum.Parse.
2) There is an implicit conversion from the actual enumeration type to the EnumValue<> type, which I don't know how to invoke with reflection.
I would like the code to end up looking something like:
PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = ConvertToPropType(pInfo.PropertyType, attr.Value); /* this
would return an instance of EnumValue<JustificationValues> in this case */
pInfo.SetValue(element, value, null);
How do I implement ConvertToPropType? Or is there a better solution?
Thanks
Edit:
I got a solution working using Earwicker's suggestion, but it relies on the convenient fact that the enumeration's type name can be derived from the node's type name ("Justification" -> "JustificationValues"). I'm still curious how to solve this in the general case, though.
Edit2:
GetGenericArguments got me the rest of the way there. Thanks.
If the attribute value is just a string, I assume you already have some way of figuring out that the string identifies a value from a specific enumeration. In your example you have it hard-coded, so I'm not sure if that's what you want or what you want to change.
Assuming you know it's an enumeration, and you know which enumeration, you already know how to get an object containing a boxed value of the right enum type, as in your snippet.
Now if I assume EnumValue<T> has a constructor that takes a T.
Type genericType = typeof(EnumValue<>);
Type concreteType = genericType.MakeGenericType(typeof(JustificationValues));
Now concreteType is the type EnumValue<JustificationValues>.
From that you can get a constructor, hopefully one that takes a JustificationValues parameter, and Invoke it.
Update
Ahh, I see what you're doing now. You use the XML attribute name to pick a C# property. You need to be able to detect whether that property is of a type EnumValue<T>, and find out what T is.
PropertyInfo p = // ... get property info
Type t = p.GetType();
if (t.IsGenericType &&
t.GetGenericTypeDefinition == typeof(EnumValue<>))
{
Type e = t.GetGenericArguments()[0]; // get first (and only) type arg
// e is the enum type...
Give that a try.
.Net 4.0 adds support to do a late bound implict or explict conversion. This is simplified in the open source framework ImpromptuInterface with it's static method called InvokeConvert. In your ideal example it would work like this:
PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = Impromptu.InvokeConvert(attr.Value, pInfo.PropertyType);
pInfo.SetValue(element, value, null);
This might only work with basic types but it was good enough for what I'm doing
PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = System.Convert.ChangeType(attr.Value, pInfo.PropertyType);
pInfo.SetValue(element, value, null);