Accessing a class field using a string - c#

I have a class name DB.IFCArray which have plenty of fields in it (name, description etc), I want to implement a function
that goes to the DB.IFCArray.field and do stuff..
public static bool if_is_a(DB.IFCArray object1, string field, string value)
{
if (object1.field == value) // this ofc not working, but hope you get the idea
return true;
return false;
}

You can of course use Reflection
//get the property indicated by parameter 'field'
//Use 'GetField' here if they are actually fields as opposed to Properties
//although the merits of a public field are dubious...
var prop = object1.GetType().GetProperty(field);
//if it exists
if (prop!=null)
{
//get its value from the object1 instance, and compare
//if using Fields, leave out the 'null' in this next line:
var propValue = prop.GetValue(object1,null);
if (propValue==null) return false;
return propValue;
}
else
{
//throw an exception for property not found
}
But as CodeCaster mentioned above, I'd recommend you take a look at your design and see if this is really necessary. What is the bigger picture here? Unless you absolutely 100% will not know the property names until runtime, there's almost always a better way...

I think error is showing due to type error in the if (object1.field == value) statement.
use reflection to get type of the field and compare the value according to the type.
Hope this helps,
Thanks.

Related

Recovering doubleĀ“s null

I have a table with a few fields, one of them is a Double type field which can contains null values...
Using ADO and SQLDATAReader I recover that field in a variable. I defined this variable as a: Double, Double?, double, double?... and I got the value (coming from de SQLDataReader) using GetValue (and doing a cast) or using a GetDouble... each one is crashing when the value is null.
The only this is working is defining this variable as a object, but I dont want it. Thinking in advance could be hard times handle this type in my project...
Quote: I have to differentiate the case when this value is 0 or null...
Any idea guys?
Edited:
Object.DoubleValue= (Double?)Datos.GetDouble(1);
Object.doubleValue= (double?)Datos.GetDouble(1);
Not working.
Object.ObjectValue= Datos.GetValue(1);
Working.
Unfortunately there's no out of the box method. But you could tweak it with an extension method like this:
(be aware its just a rough prototype that works in your case, but probably needs some checks and constraints etc)
public static class Helpers
{
public static T GetSmartValue<T>(this SqlDataReader r, int ordinal)
{
dynamic value = r.GetValue(ordinal);
if (value == DBNull.Value)
{
value = null;
return value;
}
return (T) value;
}
}
then in your code
var x = yourReader.GetSmartValue<double?>(1);

efficient way to check for changes in a "calculation" class

I have the following "calculation" class.
public class Foo
{
private int? _sum = 0;
public int Sum
{
get
{
if (_sum == null)
_sum = 1 + 1; //simple code to show "some" calculation happens...
return _sum.GetValueOrDefault();
}
}
}
In this example there is only 1 Field/Member but in my real class there are around 50 Members, that all look similar just with different value calculations.
In the class I also have a Recalc method.
This Recalc method does 4 things
Save the old values
set all fields to null
calls the getter of every member
Checks if the old values differ from the newvalues and does related stuff
I am not sure whats the best way to store the old values and check for changes with the new values.
My current implementation is this:
public string GetValuesKey()
{
//again this method only handles the 1 Member and not all 50 in real app its string.Format("{0}|{1}|{2}|...{49}|{50}|", ....);
return string.Format("{0}|", this.Sum);
}
public void Recalc()
{
var oldValues = GetValuesKey();
//set all fields to null
//call the getters
var newValues = GetValuesKey();
if (oldValues != newValues)
{
//something changed...
}
}
But with this code there is a memory/performance issue since I am doing boxing with the struct (decimal) writing to a reference type (string).
I kind of want to prevent doing 50 additional fields (something like _oldSum) for all the members.
I just need to check if any member has changed during the Recalc procedure.
Just in Case, I cannot do the following code.
public void Recalc()
{
var changes = false;
var oldValue = this.Sum;
_sum = null;
var newValue = this.Sum;
if (oldValue != newValue)
changes = true;
//check next member
oldValue = this.Sum2;
_sum2 = null;
newValue = this.Sum2;
if (oldValue != newValue)
changes = true;
//check next member and so on...
}
Since I need to set all fields to null first and only AFTER all of them have been set to null I can execute the getters, since the members are dependant on each other for exmple if the Sum Member would aggregate two other members and they havent been set to null first they would still have old values.
So I need a way to store something that represents all values before setting the fields null and after calling the getter of the members a way to check for changes.
Any help is welcome.
Edit:
Here is the code, I wrote to test performance/memory:
http://pastebin.com/3WiNJHyS
Instead of combining all values in a string and have some pefomance hit on that string construction - put all values in array (of decimal), then set all fields to null, make your calculation and compare arrays of old and new values.
If you don't want to write yourself all the 50 _oldValue fields, the only alternative is to use Reflection, that implies some boxing/unboxing, so performance will not be the best possible.
Anyway, in the following implementation I assume that in the Foo class the members that are involved in the calculation are all and the only ones that are properties of type decimal?.
Otherwise, we need a more complicated solution, with BindingFlags, and/or Attribute on every field/property involved, and so on.
public void Recalc()
{
var propertyInfos = GetType()
.GetProperties()
.Where(pInfo => pInfo.PropertyType.IsValueType);
var fieldInfos = GetType()
.GetFields()
.Where(fInfo => fInfo.FieldType.IsValueType);
//create a dictionary with all the old values
//obtained from the backing fields.
var oldValueDictionary = fieldInfos.ToDictionary(
fInfo => fInfo.Name,
fInfo => (decimal?)fInfo.GetValue(this));
//set all properties to null
foreach (var pInfo in propertyInfos)
pInfo.SetValue(this, null);
//call all the getters to calculate the new values
foreach (var pInfo in propertyInfos)
pInfo.GetValue(this);
//compare new field values with the old ones stored in the dictionary;
//if only one different is found, the if is entered.
if (fieldInfos.Any(fInfo =>
(decimal?)fInfo.GetValue(this) != oldValueDictionary[fInfo.Name]))
{
//do stuffs
}
}
As a final note, your class configuration is very strange. Are you sure that setting all the calculations in the getters is the best choice? Maybe you should re-think about you design. One task is to retrieve a property value (a getter), another task is to calculate something (starting from some value stored in the backing fields)...

Compare 2 object of the same class

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:

Store a null in System.Web.HttpContext.Current.Cache

In an MVC App we are suppose to dynamically load some strings from database. Basically a <string,string> key-value dictionary. Loading each text each time from the database would kill the application, so those texts would normally be pulled from the DB just once and then stored in cache (namely Web.HttpContext.Current.Cache). There are also default texts that are hardcoded and those would be used if nothing was found in the database. To make things more simple I would also put those default texts in the cache.
The logic is as follows:
Try getting the text from cache and return it if it's found.
If there was no text in the cache, try pulling it from the databaseand and if it's found, save it to cache and return it.
If all above failed, use the default text and save it to the cache so no further queries will be made for this particular key.
If I understand it correctly the only way to check if key is set in Web.HttpContext.Current.Cache is by comparing it's value to a null. My problem is, it's not entirely unlikely that the default text will be a null. So if I put that in the cache, I will not know that the key was set and I will try to pull the non-existant value from the database each time the text is needed.
I know I could use an empty string instead of a null, but it's possible that I might need to distinguish between nulls and empty strings for some reason in the near future.
So is there some way to tell if a key is set in the Web.HttpContext.Current.Cache when the value assigned is a null?
StriplingWarrior beat me to the punch, but I agree with what he said: just wrap what you're storing in a complex type so you can do a null check. Normally you'd use Nullable<T> for this, but you can't use a Nullable type for things that are already considered nullable, like strings.
Here's a practical example:
Define a simple wrapper class:
public class CacheEntry<T>
{
public T Value { get; private set; }
public CacheEntry(T value)
{
Value = value;
}
}
And then use it!
System.Web.HttpContext.Current.Cache.Insert("name", new CacheEntry<string>("Marcin"));
var name = (CacheEntry<string>) System.Web.HttpContext.Current.Cache.Get("name");
if (name != null)
{
Console.WriteLine(name.Value);
}
null is highly overused by most C# developers. If you recognize that these values are optional (meaning they may or may not be there), you may want to make your cache entries be of some type that wraps the actual type you're storing. That way, getting a null value means that there is no entry, whereas getting a non-null value that has a null Value property on it means it exists in the cache, but its value is null.
Incidentally, I've been working on a library to represent exactly this sort of wrapper. It's still in its alpha phases at the moment, but at least for this purpose it should be safe to use. You can get it from Nuget under the name "CallMeMaybe".
object result = HttpContext.Current.Cache.Get(key);
if(result != null)
{
return ((Maybe<string>)result).Else(() => null);
}
var value = Maybe.From(GetValueFromDb());
HttpContext.Current.Cache.Add(key, value, ...);
return value;
Another option would be to use MemoryCache directly, which I think is what backs the HttpContext.Current.Cache these days, but which provides additional methods like GetCacheItem.
If you must store a null in something that doesn't distinguish between nulls and key-not-found conditions, store an "active null" object to represent a null you've actually added:
private static readonly object ActiveNull = new object();
public bool GetIfPresent(string key, out object value)
{
object fromCache = Web.HttpContext.Current.Cache.Get(key);
if(fromCache == null)
{
//failed to obtain.
value = null;
return false;
}
if(ReferenceEquals(fromCache, ActiveNull))
{
//obtained value representing null.
value = null;
return true;
}
value = fromCache;
return true;
}
public void AddToCache(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
{
Web.HttpContext.Current.Cache.Add(key, value ?? ActiveNull, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback);
}

Writing a certain generic method

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);
)

Categories