Check if a property has a specific attribute? - c#

I'm using WCF RIA services to do a few small pieces of a web application; mainly populate/filter lists (I don't understand RIA well enough yet to trust I'm doing server side validation correct). One of the things I do is get a list of which fields have which generic type, by which I mean, strings are a text type, decimal, double, integer are numeric, etc. I do that with a LINQ query
Fields = type.GetProperties().Where(pi => pi.PropertyType == typeof(string) && pi.GetGetMethod() != null && pi.Name != "DisplayName")
.Select(pi => new FieldData
{
FieldName = CommonResources.AddSpacesToSentence(pi.Name, true),
FieldType = "Text"
}).....
The field DisplayName is a special field that should be ignored in lists, but as this application is growing I realize this isn't a very maintainable/expandable/buzzwordable way to go about this. What I really want is to know is if metadata for the DisplayName property has the attribute [Display(AutoGenerateField = false)]
Is there a way I can check for that in my LINQ?
Update:
After posting this I was able to slowly work out how to do this (I've never worked with Attributes in this way before). The answer given by King King looks nice and is very generic, but the way I wound up solving this was different, so if you're interested in another way, here's what I found. I added this to the LINQ query:
((DisplayAttribute)Attribute.GetCustomAttribute(pi, typeof(DisplayAttribute))).GetAutoGenerateField() == false

You can use the GetCustomAttributes method to filter properties with the given attribute:
...
.Where(pi => pi.GetCustomAttributes(typeof(DisplayAttribute), true).Any())
...
The true argument includes inheritance in attribute search.

You can try the following code the check against an attribute value of a property:
public bool CheckPropertyAttribute(Type type, string property,
Type attributeType, string attProp, object value)
{
var prop = type.GetProperty(property);
if (prop == null) return false;
return CheckPropertyAttribute(prop, attributeType, attProp, value);
}
public bool CheckPropertyAttribute(PropertyInfo prop, Type attributeType,
string attProp, object value){
var att = prop.GetCustomAttributes(attributeType, true);
if (att == null||!att.Any()) return false;
var attProperty = attributeType.GetProperty(attProp);
if (attProperty == null) return false;
return object.Equals(attProperty.GetValue(att[0], null),value);
}
Usage::
if(CheckPropertyAttribute(pi, typeof(DisplayAttribute), "AutoGenerateField", false)){
//...
}
NOTE: I provided 2 overloads, but in your case I think you just need to use the second overload (the case in which we already have some PropertyInfo).

Related

Null check for all class members in effective way

Working in WCF service. I have class called Customer with 10 fields. I want to ensure at least one should have value.
Unfortunately the class is not null but all the class members are null from the input request
Is there any simple and effect way to check to confirm at least one class field has value rather checking field1.IsnotNullOrEmpty() & field2.IsnotnullOrEmpty()......field10.IsnotNullOrEmpty()
You can iterate all properties like this (just short sample of code)
bool HasValue<T>(T obj)
{
var type = typeof(T);
return type.GetProperties().Where(p =>
{
var val = p.GetValue(obj);
if (val is string) return !string.IsNullOrEmpty(val as string);
return val != null;
}).Any();
}
But as was said, your way is simpler and more efficient.

Comparing two equal vars return false

Some background to understand the code. I have an MVC application, all my models implement IModel. IModel just enforces to have an int Id property.
The following method "updates" an instances of a model with the data available in a viewmodel. For each property of the viewmodel it checks if a corresponding property exists in the model, if it does It updates the value in the model with those of the viewmodel, if the values are different.
At the last point it goes wrong. The statement : OldValue != NewValue always returns true, even if f.e. both are integers, 1. Why ?
public static Boolean UpdateIfChanged<M, VM>(this M Model, VM ViewModel) where M : IModel
{
Boolean HasUpdates = false;
Type Mtype = typeof(M);
PropertyInfo[] MProperties = Mtype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
Type VMtype = typeof(VM);
PropertyInfo[] VMProperties = VMtype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var VMProperty in VMProperties)
{
if (!VMProperty.PropertyType.GetInterfaces().Any(x => x.Name == typeof(IModel).Name)
&& MProperties.Any(x => x.Name == VMProperty.Name)
&& Mtype.GetProperty(VMProperty.Name).PropertyType == VMProperty.PropertyType )
{
var OldValue = Mtype.GetProperty(VMProperty.Name).GetValue(Model);
var NewValue = VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel);
if (NewValue != null)
{
if (OldValue == null)
{
Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue);
HasUpdates = true;
}
else
{
if (OldValue != NewValue)
{
Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue);
HasUpdates = true;
}
}
}
}
}
return HasUpdates;
}
The problem here is that OldValue and NewValue are objects at compile time, not int, and therefore the ==/!= operators call the ones defined by the object class, because all operators are static. The object operators check for referential equality, not logical equality, and thus only check if the two arguments are exactly the same object (the same pointer in C++)
To get around this, you have several options
As Tigran mentioned, type cast the values coming out, so you end up using the operator defined in int instead of object
Call object.Equals(OldValue, NewValue), which checks for null and then calls the virtual Object.Equals(object o), which thus will call the function defined in the actual class/struct of the calling object (in this case int)
your GetValue(..) call returns boxed integer object, so reference type.
Hence your code:
//OldValue and NewValue are Object types and NOT integers !
if (OldValue != NewValue)
compares references and not values.
You didn't notice that as you are using var keyword, which "hides" concrete type.
To correctly overcome this issue, may do like:
....
var OldValue = (int)Mtype.GetProperty(VMProperty.Name).GetValue(Model); //cast to int
var NewValue = (int)VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel);//cast to int
....
Try this if (OldValue.ToString() != NewValue.ToString()). Or if OldValue/NewValue are int-s: if ((int)OldValue != (int)NewValue)
A better syntax would be:
if (!Equals(OldValue, NewValue))

Passing properties as parameters to be Got and Set

Well, I need to repeat same code for many properties.
I've seen examples taking Action delegates, but they don't fit quite well here.
I want something like this: (see explanation below)
Dictionary<Property, object> PropertyCorrectValues;
public bool CheckValue(Property P) { return P.Value == PropertyCorrectValues[P]; }
public void DoCorrection(Property P) { P.Value = PropertyCorrectValues[P]; }
.
I want to have a dictionary containing many properties and their respective "correct" values. (I know it's not well declared, but that's the idea). Properties are not necessarely inside my class, some of them are in objects of different assemblies.
A method bool CheckValue(Property). This method must access the actual value of the property and compare to the correct value.
And a method a void DoCorrection(Property). This one sets the property value to the correct value.
Remember I have many of those properties, I wouldn't like to call the methods by hand for each property. I'd rather iterate through the dicionary in a foreach statement.
So, the main question is in the title.
I've tried the by ref, but properties don't accept that.
Am I obligated to use reflection??? Or is there another option (if I need, reflection answer will be accepted as well).
Is there anyway I can make a dictionary with pointers in C#? Or some kind of assignment that changes the value of variable's target instead of changing the target to another value?
Thanks for the help.
You can do this using reflection. Get a list of the properties on the object of interest with typeof(Foo).GetProperties(). Your PropertyCorrectValues property can have type IDictionary<PropertyInfo, object>. Then use the GetValue and SetValue methods on PropertyInfo to perform the desired operations:
public bool CheckProperty(object myObjectToBeChecked, PropertyInfo p)
{
return p.GetValue(myObjectToBeChecked, null).Equals(PropertyCorrectValues[p]);
}
public void DoCorrection(object myObjectToBeCorrected, PropertyInfo p)
{
p.SetValue(myObjectToBeCorrected, PropertyCorrectValues[p]);
}
In addition to Ben's code I'd like to contribute the following code fragment:
Dictionary<string,object> PropertyCorrectValues = new Dictionary<string,object>();
PropertyCorrectValues["UserName"] = "Pete"; // propertyName
PropertyCorrectValues["SomeClass.AccountData"] = "XYZ"; // className.propertyName
public void CheckAndCorrectProperties(object obj) {
if (obj == null) { return; }
// find all properties for given object that need to be checked
var checkableProps = from props
in obj.GetType().GetProperties()
from corr in PropertyCorrectValues
where (corr.Key.Contains(".") == false && props.Name == corr.Key) // propertyName
|| (corr.Key.Contains(".") == true && corr.Key.StartsWith(props.DeclaringType.Name + ".") && corr.Key.EndsWith("." + props.Name)) // className.propertyName
select new { Property = props, Key = corr.Key };
foreach (var pInfo in checkableProps) {
object propValue = pInfo.Property.GetValue(obj, null);
object expectedValue = PropertyCorrectValues[pInfo.Key];
// checking for equal value
if (((propValue == null) && (expectedValue != null)) || (propValue.Equals(expectedValue) == false)) {
// setting value
pInfo.Property.SetValue(obj, expectedValue, null);
}
}
}
When using this "automatic" value correction you might also consider:
You cannot create a PropertyInfo object just by knowing the property name and independently of the declaring class; that's why I chose string for the key.
When using the same property name in different classes then you might need to change the code that is doing the actual assignment because the type between the correct value and the property type might differ.
Using the same property name in different classes will always perform the same check (see point above), so you might need a syntax for property names to restrict it to a specific class (simple dot notation, doesn't work for namespaces or inner classes, but might be extended to do so)
If needed you can replace the "check" and "assign" part with separate method calls, but it might be done inside the code block as stated in my example code.

Getting 'basic' datatype rather than weird nullable one, via reflection in c#

My basic need is to get the datatypes from an anonymous type generated from a LINQ to SQL query.
I have a piece of code (cleverer than I could write, since I haven't really delved into reflection) which returns the datatypes from an anonymous types, and works perfectly for the elements marked 'not nullable' in the linq2sql properties. So, if I have a string it will return as System.String. However, when the element is nullable I end up with the 'full name' of it being:
{Name = "Nullable1" FullName = "System.Nullable1[[System.Decimal, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}
All I want to extract is the System.Decimal type in such a case (and in cases of strings or whatever, I'd just want System.String). I've looked through the properties and can't find anything that seems to store this.
private static Dictionary<string, Type> GetFieldsForType<T>(IEnumerable<T> data)
{
object o = data.First();
var properties = o.GetType().GetProperties();
return properties.ToDictionary(property => property.Name, property => property.PropertyType);
}
The LINQ query (which I don't think really matters here):
var theData = from r in db.tblTestEdits select new { myitem = r.textField, mydecimal = r.decimalField };
I found this link that seems to try to address a similar thing.
http://ysgitdiary.blogspot.com/2010/02/blog-post.html
Though it seems to return a "string" of what the type is rather than the actual type, which is what I need. Not sure how to convert such a thing.
Many thanks all.
private static Type GetCoreType(Type type)
{
if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>))
return Nullable.GetUnderlyingType(type);
else
return type;
}
You want something like this maybe
Type targetType;
bool isNullable;
// Do we have a nullable type?
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
isNullable = true;
targetType = type.GetGenericArguments()[0];
}
else
{
isNullable = false;
targetType = type;
}

Testing if an Object is a Dictionary in C#

Is there a way to test if an object is a dictionary?
In a method I'm trying to get a value from a selected item in a list box. In some circumstances, the list box might be bound to a dictionary, but this isn't known at compile time.
I would like to do something similar to this:
if (listBox.ItemsSource is Dictionary<??>)
{
KeyValuePair<??> pair = (KeyValuePair<??>)listBox.SelectedItem;
object value = pair.Value;
}
Is there a way to do this dynamically at runtime using reflection? I know it's possible to use reflection with generic types and determine the key/value parameters, but I'm not sure if there's a way to do the rest after those values are retrieved.
Check to see if it implements IDictionary.
See the definition of System.Collections.IDictionary to see what that gives you.
if (listBox.ItemsSource is IDictionary)
{
DictionaryEntry pair = (DictionaryEntry)listBox.SelectedItem;
object value = pair.Value;
}
EDIT:
Alternative when I realized KeyValuePair's aren't castable to DictionaryEntry
if (listBox.DataSource is IDictionary)
{
listBox.ValueMember = "Value";
object value = listBox.SelectedValue;
listBox.ValueMember = ""; //If you need it to generally be empty.
}
This solution uses reflection, but in this case you don't have to do the grunt work, ListBox does it for you. Also if you generally have dictionaries as data sources you may be able to avoid reseting ValueMember all of the time.
It should be something like the following. I wrote this in the answer box so the syntax may not be exactly right, but I've made it Wiki editable so anybody can fix up.
if (listBox.ItemsSource.IsGenericType &&
typeof(IDictionary<,>).IsAssignableFrom(listBox.ItemsSource.GetGenericTypeDefinition()))
{
var method = typeof(KeyValuePair<,>).GetProperty("Value").GetGetMethod();
var item = method.Invoke(listBox.SelectedItem, null);
}
I know this question was asked many years ago, but it is still visible publicly.
There were few examples proposed here in this topic and in this one:
Determine if type is dictionary [duplicate]
but there are few mismatches, so I want to share my solution
Short answer:
var dictionaryInterfaces = new[]
{
typeof(IDictionary<,>),
typeof(IDictionary),
typeof(IReadOnlyDictionary<,>),
};
var dictionaries = collectionOfAnyTypeObjects
.Where(d => d.GetType().GetInterfaces()
.Any(t=> dictionaryInterfaces
.Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition())))
Longer answer:
I believe this is the reason why people make mistakes:
//notice the difference between IDictionary (interface) and Dictionary (class)
typeof(IDictionary<,>).IsAssignableFrom(typeof(IDictionary<,>)) // true
typeof(IDictionary<int, int>).IsAssignableFrom(typeof(IDictionary<int, int>)); // true
typeof(IDictionary<int, int>).IsAssignableFrom(typeof(Dictionary<int, int>)); // true
typeof(IDictionary<,>).IsAssignableFrom(typeof(Dictionary<,>)); // false!! in contrast with above line this is little bit unintuitive
so let say we have these types:
public class CustomReadOnlyDictionary : IReadOnlyDictionary<string, MyClass>
public class CustomGenericDictionary : IDictionary<string, MyClass>
public class CustomDictionary : IDictionary
and these instances:
var dictionaries = new object[]
{
new Dictionary<string, MyClass>(),
new ReadOnlyDictionary<string, MyClass>(new Dictionary<string, MyClass>()),
new CustomReadOnlyDictionary(),
new CustomDictionary(),
new CustomGenericDictionary()
};
so if we will use .IsAssignableFrom() method:
var dictionaries2 = dictionaries.Where(d =>
{
var type = d.GetType();
return type.IsGenericType && typeof(IDictionary<,>).IsAssignableFrom(type.GetGenericTypeDefinition());
}); // count == 0!!
we will not get any instance
so best way is to get all interfaces and check if any of them is dictionary interface:
var dictionaryInterfaces = new[]
{
typeof(IDictionary<,>),
typeof(IDictionary),
typeof(IReadOnlyDictionary<,>),
};
var dictionaries2 = dictionaries
.Where(d => d.GetType().GetInterfaces()
.Any(t=> dictionaryInterfaces
.Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition()))) // count == 5
you can check to see if it implements IDictionary. You'll just have to enumerate over using the DictionaryEntry class.
I'm coming from Determine if type is dictionary, where none of the answers there adequately solve my issue.
The closest answer here comes from Lukas Klusis, but falls short of giving a IsDictionary(Type type) method. Here's that method, taking inspiration from his answer:
private static Type[] dictionaryInterfaces =
{
typeof(IDictionary<,>),
typeof(System.Collections.IDictionary),
typeof(IReadOnlyDictionary<,>),
};
public static bool IsDictionary(Type type)
{
return dictionaryInterfaces
.Any(dictInterface =>
dictInterface == type || // 1
(type.IsGenericType && dictInterface == type.GetGenericTypeDefinition()) || // 2
type.GetInterfaces().Any(typeInterface => // 3
typeInterface == dictInterface ||
(typeInterface.IsGenericType && dictInterface == typeInterface.GetGenericTypeDefinition())));
}
// 1 addresses public System.Collections.IDictionary MyProperty {get; set;}
// 2 addresses public IDictionary<SomeObj, SomeObj> MyProperty {get; set;}
// 3 (ie the second .Any) addresses any scenario in which the type implements any one of the dictionaryInterfaces Types.
The issues with the other answers - assuming they address #3 - is that they don't address #1 and #2. Which is understandable, since getting and checking a Property's Type probably isn't a common scenario. But in case you're like me, and that scenario is part of your use-case, there you go!
You could be a little more generic and ask instead if it implements IDictionary. Then the KeyValue collection will contina plain Objects.
I believe a warning is at place.
When you're testing if an object 'is a' something this or that, you're reimplementing (part of) the type system. The first 'is a' is often swiftly followed by a second one, and soon your code is full of type checks, which ought to be very well handled by the type system - at least in an object oriented design.
Of course, I know nothing of the context of the question. I do know a 2000 line file in our own codebase that handles 50 different object to String conversions... :(
if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType()))
{
}

Categories

Resources