How do I add a attribute to a XmlArray element ( not to XmlArrayItem ) while serializing the object?
XmlArray is used to tell the xmlserializer to treat the property as array and serialize it according its parameters for the element names.
[XmlArray("FullNames")]
[XmlArrayItem("Name")]
public string[] Names{get;set;}
will give you
<FullNames>
<Name>Michael Jackson</Name>
<Name>Paris Hilton</Name>
</FullNames>
In order to add an xml attribute to FullNames element, you need declare a class for it.
[XmlType("FullNames")]
public class Names
{
[XmlAttribute("total")]
public int Total {get;set;}
[XmlElement("Name")]
public string[] Names{get;set;}
}
This will give you
<FullNames total="2">
<Name>Michael Jackson</Name>
<Name>Paris Hilton</Name>
</FullNames>
This can be done by deriving from IXmlSerializable. I have attached a sample with a base class which does the job:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace XmlSerializerApp {
class Program {
static void Main() {
using (var ms = new MemoryStream()) {
var serializer = new XmlSerializer(typeof(RootObject));
serializer.Serialize(ms, new RootObject());
ms.Position = 0;
var formatted =
new XmlDocument {
XmlResolver = null,
PreserveWhitespace = false
};
formatted.Load(ms);
var stringWriter = new StringWriter();
var xmlTextWriter =
new XmlTextWriter(stringWriter) {Formatting = Formatting.Indented};
formatted.WriteTo(xmlTextWriter);
Console.WriteLine(stringWriter.ToString());
ms.Position = 0;
var rootObj = serializer.Deserialize(ms) as RootObject;
if (rootObj?.Children != null) {
Console.WriteLine($"Whatever: {rootObj?.Children?.Whatever}");
foreach (var child in rootObj.Children) {
if (child == null) {
continue;
}
Console.WriteLine($" {child.Name}={child.Value}");
}
}
}
}
}
[XmlRoot(ElementName = "root")]
public class RootObject{
[XmlAttribute(AttributeName = "version")]
public string Version {get; set;} = "1.0.0";
[XmlElement(ElementName = "children")]
public ListOfChildren Children {get; set;} = new ListOfChildren {
new Child{ Name = "one", Value = "firstValue"}
};
}
[XmlRoot(ElementName = "add")]
public class Child {
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "value")]
public string Value { get; set; }
}
public class ListOfChildren : ListBase<Child> {
[XmlAttribute(AttributeName = "whatever")]
public bool Whatever { get; set; } = true;
}
public class ListBase<T>
: List<T>
, IXmlSerializable
{
private static readonly Type _s_type = typeof(T);
// ReSharper disable once StaticMemberInGenericType
private static readonly XmlAttributeOverrides _s_overrides =
new Func<XmlAttributeOverrides>(
() => {
var overrides = new XmlAttributeOverrides();
overrides.Add(_s_type, new XmlAttributes{ XmlRoot = new XmlRootAttribute("add")});
return overrides;
})();
// ReSharper disable once StaticMemberInGenericType
private static readonly XmlSerializer _s_serializer = new XmlSerializer(_s_type, _s_overrides);
/// <inheritdoc />
public XmlSchema GetSchema() { throw new NotImplementedException(); }
/// <inheritdoc />
public void ReadXml(XmlReader reader) {
var localName = reader.LocalName;
var prefix = reader.Prefix;
var namespaceUri = reader.NamespaceURI;
var depth = reader.Depth;
var attributes =
GetAttributes()?.ToArray()
?? Array.Empty<KeyValuePair<PropertyInfo, XmlAttributeAttribute>>();
while (reader.MoveToNextAttribute()) {
var attribute =
attributes
.Where(
a =>
string.Equals(
a.Value?.AttributeName,
reader.LocalName,
StringComparison.Ordinal)
&& string.Equals(
a.Value?.Namespace ?? string.Empty,
reader.NamespaceURI,
StringComparison.Ordinal)
)
.Select(x => x.Key)
.FirstOrDefault();
if (attribute != null) {
var attributeValue = reader.Value;
if (attribute.PropertyType == typeof(string)) {
attribute.SetValue(attributeValue, null);
}
else if (attribute.PropertyType == typeof(bool)) {
if ("1".Equals(attributeValue, StringComparison.Ordinal)
|| "-1".Equals(attributeValue, StringComparison.Ordinal)
|| "TRUE".Equals(attributeValue, StringComparison.OrdinalIgnoreCase)) {
attribute.SetValue(this, true);
}
}
else if (attribute.PropertyType == typeof(short)
&& short.TryParse(attributeValue, out var shortValue)) {
attribute.SetValue(this, shortValue);
}
else if (attribute.PropertyType == typeof(int)
&& int.TryParse(attributeValue, out var intValue)) {
attribute.SetValue(this, intValue);
}
else if (attribute.PropertyType == typeof(long)
&& long.TryParse(attributeValue, out var longValue)) {
attribute.SetValue(this, longValue);
}
else if (attribute.PropertyType == typeof(decimal)
&& decimal.TryParse(attributeValue, out var decimalValue)) {
attribute.SetValue(this, decimalValue);
}
else if (attribute.PropertyType == typeof(float)
&& float.TryParse(attributeValue, out var floatValue)) {
attribute.SetValue(this, floatValue);
}
else if (attribute.PropertyType == typeof(double)
&& double.TryParse(attributeValue, out var doubleValue)) {
attribute.SetValue(this, doubleValue);
}
else if (attribute.PropertyType == typeof(Guid)
&& Guid.TryParse(attributeValue, out var guidValue)) {
attribute.SetValue(this, guidValue);
}
else if (attribute.PropertyType == typeof(Version)
&& Version.TryParse(attributeValue, out var versionValue)) {
attribute.SetValue(this, versionValue);
}
else if (attribute.PropertyType == typeof(Uri)
&& Uri.TryCreate(
attributeValue,
UriKind.RelativeOrAbsolute,
out var uriValue)) {
attribute.SetValue(this, uriValue);
}
}
}
Clear();
while (reader.Read()) {
if (reader.NodeType != XmlNodeType.Element) {
if (reader.NodeType == XmlNodeType.EndElement
&& prefix.Equals(reader.Prefix, StringComparison.Ordinal)
&& localName.Equals(reader.LocalName, StringComparison.Ordinal)
&& namespaceUri.Equals(reader.NamespaceURI, StringComparison.Ordinal)
&& depth == reader.Depth
) {
break;
}
continue;
}
var x = reader.ReadSubtree();
var item = (T)_s_serializer?.Deserialize(x);
Add(item);
}
}
/// <inheritdoc />
public void WriteXml(XmlWriter writer) {
var enumerable = GetAttributes();
if (enumerable != null) {
foreach (var attribute in enumerable) {
if (attribute.Key == null || attribute.Value?.AttributeName == null) {
continue;
}
var value = attribute.Key.GetValue(this, null);
if (value is bool b) {
value = b
? "true"
: "false";
}
if (value != null) {
writer.WriteAttributeString(attribute.Value.AttributeName,
attribute.Value.Namespace,
value.ToString() ?? string.Empty
);
}
}
}
foreach (var item in this) {
if (item == null) {
continue;
}
_s_serializer?.Serialize(writer, item);
}
}
private IEnumerable<KeyValuePair<PropertyInfo, XmlAttributeAttribute>> GetAttributes() {
return GetType()
.GetProperties()
.Select(
p =>
new KeyValuePair<PropertyInfo, XmlAttributeAttribute>(
p,
p.GetCustomAttributes(
typeof(XmlAttributeAttribute),
true)
.Cast<XmlAttributeAttribute>()
.FirstOrDefault())
)
.Where(x => x.Value != null);
}
}
}
Related
I'm trying to use reflection to compare properties of objects that are the same type.
The problem is that with reference types <T> == <T> won't do So I try to use reflection to compare values of IEnumerable for this I try to invoke Enumerable.Except(T)
It works on List but won't work for Dictionaries:
Unable to cast object of type
'd__571[System.Collections.Generic.KeyValuePair2[System.String,System.String]]'
to type 'System.Collections.Generic.IEnumerable`1[System.Object]'.
The issue is with this code :
var typeKeyValuePair = typeof(KeyValuePair<,>);
Type[] typeArgs = { args[0], args[1] };
exceptMethods = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(mi => mi.Name == "Except")
?.MakeGenericMethod(typeKeyValuePair.MakeGenericType(typeArgs));
Full code for the info
public static List<Variance> DetailedCompare<T>(this T val1, T val2)
{
List<Variance> variances = new List<Variance>();
PropertyInfo[] propertyInfo = val1.GetType().GetProperties();
foreach (PropertyInfo p in propertyInfo)
{
Variance v = new Variance();
v.Prop = p.Name;
v.valA = p.GetValue(val1);
v.valB = p.GetValue(val2);
switch (v.valA)
{
case null when v.valB == null:
continue;
case null:
variances.Add(v);
continue;
}
if (v.valA.Equals(v.valB)) continue;
if (typeof(IEnumerable).IsAssignableFrom(p.PropertyType))
{
//string
if (p.PropertyType == typeof(string))
{
variances.Add(v);
continue;
}
var args = p.PropertyType.GetGenericArguments();
MethodInfo exceptMethods = null;
if (args.Length == 2) //dictionaries
{
variances.Add(v); // add to difference while not able to compare
/*
var typeKeyValuePair = typeof(KeyValuePair<,>);
Type[] typeArgs = { args[0], args[1] };
exceptMethods = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(mi => mi.Name == "Except")
?.MakeGenericMethod(typeKeyValuePair.MakeGenericType(typeArgs));*/
}
else if (args.Length == 1)//lists
{
exceptMethods = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(mi => mi.Name == "Except")
?.MakeGenericMethod(p.PropertyType.GetGenericArguments().FirstOrDefault());
}
else//not
{
variances.Add(v);
}
if (exceptMethods != null)
{
try
{
var res1 = (IEnumerable<object>)exceptMethods.Invoke(v.valA, new[] { v.valA, v.valB });
var res2 = (IEnumerable<object>)exceptMethods.Invoke(v.valB, new[] { v.valB, v.valA });
if (res1.Any() != res2.Any()) variances.Add(v);
}
catch (Exception ex)
{
}
/* if (v.valA.Except(v.valB).Any() || v.valB.Except(v.valA).Any())
{
variances.Add(v);
}*/
}
}
}
return variances;
}
}
class Variance
{
public string Prop { get; set; }
public object valA { get; set; }
public object valB { get; set; }
}
I think you might consider casting to the generic IEnumerable, and then boxing it to objects with the .OfType overloading function. The complete code would look like this:
void TestFunction()
{
var v1 = new { yes = "asdf", no = "as", ar = new List<int>() { 1, 2, 3 }, dict = new Dictionary<object, object>() { { 1, 1 }, { 2, 2 } } };
var v2 = new { yes = "asdf", no = "fd", ar = new List<int>() { 1, 2, 3 }, dict = new Dictionary<object, object>() { { 1, 1 }, { 2, 2 } } };
var differences = DetailedCompare(v1, v2);
}
public static List<Variance> DetailedCompare<T>(T val1, T val2)
{
List<Variance> variances = new List<Variance>();
PropertyInfo[] proppertyInfo = val1.GetType().GetProperties();
foreach (PropertyInfo p in proppertyInfo)
{
Variance v = new Variance();
v.Prop = p.Name;
v.valA = p.GetValue(val1);
v.valB = p.GetValue(val2);
switch (v.valA)
{
case null when v.valB == null:
continue;
case null:
variances.Add(v);
continue;
}
if (v.valA.Equals(v.valB)) continue;
if (typeof(IEnumerable).IsAssignableFrom(p.PropertyType))
{
//string
if (p.PropertyType == typeof(string))
{
variances.Add(v);
continue;
}
var args = p.PropertyType.GetGenericArguments();
MethodInfo exceptMethods = null;
if (args.Length == 2) //dictionaries
{
//variances.Add(v); // add to difference while not able to compare
var typeKeyValuePair = typeof(KeyValuePair<,>);
Type[] typeArgs = { args[0], args[1] };
exceptMethods = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(mi => mi.Name == "Except")
?.MakeGenericMethod(typeKeyValuePair.MakeGenericType(typeArgs));
}
else if (args.Length == 1)//lists
{
exceptMethods = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(mi => mi.Name == "Except")
?.MakeGenericMethod(p.PropertyType.GetGenericArguments().FirstOrDefault());
}
else//not
{
variances.Add(v);
}
if (exceptMethods != null)
{
try
{
var res1 = (IEnumerable)exceptMethods.Invoke(v.valA, new[] { v.valA, v.valB });
var res2 = (IEnumerable)exceptMethods.Invoke(v.valB, new[] { v.valB, v.valA });
// TODO: maybe implement better comparisson
if (res1.OfType<object>().Any() != res2.OfType<object>().Any()) variances.Add(v);
}
catch (Exception ex)
{
}
/* if (v.valA.Except(v.valB).Any() || v.valB.Except(v.valA).Any())
{
variances.Add(v);
}*/
}
}
}
return variances;
}
public class Variance
{
public string Prop { get; set; }
public object valA { get; set; }
public object valB { get; set; }
public override string ToString() => $" Property {Prop} is either {valA} resp. {valB}";
}
I have two classes XmlPerson and Person, each class has public properties, no methods nor any fields.
How would I deep copy all the properties from Person to XmlPerson? I dont want to use a third-party library like MiscUtil.PropertyCopy or Automapper. I have managed to copy the "first-level" properties that are primitive types and strongly typed objects but when it comes the List I have no idea.
The structure of the Person class is below:
public class Person
{
public string FirstName { get; set; }
public string Surname { get; set; }
public decimal? Salary { get; set; }
public List<AddressDetails> AddressDetails { get; set; }
public NextOfKin NextOfKin { get; set; }
}
public class NextOfKin
{
public string FirstName { get; set; }
public string Surname { get; set; }
public string ContactNumber { get; set; }
public List<AddressDetails> AddressDetails { get; set; }
}
public class AddressDetails
{
public int HouseNumber { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
}
thank u for the help.
charles
Here is the what I have so far:
public class XmlTestCaseToClassMapper
{
internal TTarget MapXmlClassTotargetClass(TSource xmlPerson)
{
var targetObject = Activator.CreateInstance();
var sourceObject = Activator.CreateInstance();
//var xmlClassProperties = xmlPerson.GetType().GetProperties().ToList().OrderBy(x => x.Name);
var xmlClassProperties = GetProperties(xmlPerson.GetType());
//var targetClassProperties = targetObject.GetType().GetProperties().ToList().OrderBy(x => x.Name);
var targetClassProperties = GetProperties(targetObject.GetType());
PropertyInfo targetClassProperty = null;
foreach (var xmlProperty in xmlClassProperties)
{
if (!xmlProperty.PropertyType.IsClass || xmlProperty.PropertyType.UnderlyingSystemType == typeof(string)
|| xmlProperty.PropertyType.IsPrimitive)
{
targetClassProperty = targetClassProperties.ToList().FirstOrDefault(x => x.Name == xmlProperty.Name);
var propertyValue = xmlProperty.GetValue(xmlPerson, null);
targetClassProperty.SetValue(targetObject, propertyValue, null);
}
else if (xmlProperty.PropertyType.UnderlyingSystemType == typeof(NextOfKin)) //Check subType of the property
{
var subPropertyInstance = Activator.CreateInstance(xmlProperty.GetType());
var subProperties = GetProperties(xmlProperty.GetType());
subProperties.ForEach(subProperty =>
{
targetClassProperty = targetClassProperties.ToList().FirstOrDefault(x => x.Name == subProperty.Name && x.GetType().IsClass);
targetClassProperty.SetValue(subPropertyInstance, xmlProperty.GetValue(this, null), null);
});
}
//else if (xmlProperty.PropertyType.IsGenericType)
//{
// var xmlGenericType = xmlProperty.PropertyType.GetGenericArguments().First();
// var xmlGenericTypeProperties = GetProperties(xmlGenericType);
// targetClassProperty = targetClassProperties.ToList().FirstOrDefault(x => x.Name == xmlProperty.Name);
// var targetGenericType = targetClassProperty.PropertyType.GetGenericArguments().First();
// var targetGenericProperties = GetProperties(targetGenericType);
// Type targetGenericList = typeof(List<>).MakeGenericType(new Type[] { targetGenericType });
// object listInstance = Activator.CreateInstance(targetGenericList);
// //foreach (var xmlGenericProperty in xmlGenericTypeProperties)
// //{
// // var targetGenericProperty = targetGenericProperties.FirstOrDefault(x => x.Name == xmlGenericProperty.Name);
// // targetGenericProperty.SetValue(targetGenericProperty, xmlGenericProperty.GetValue(xmlGenericType, null), null);
// //}
// xmlGenericTypeProperties.ForEach(x =>
// {
// foreach (var targetGenericProperty in targetGenericProperties)
// {
// targetGenericProperty.SetValue(targetGenericProperty, targetGenericProperty.GetValue(x, null), null);
// }
// });
//}
//}
}
return targetObject;
}
private List<PropertyInfo> GetProperties(Type targetType)
{
var properties = new List<PropertyInfo>();
targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList().ForEach(property =>
{
properties.Add(property);
});
return properties.OrderBy(x => x.Name).ToList();
}
}
Here is a possible solution. It probably requires some tweaks based on your actual classes.
public T DeepCopy<S, T>(S source) where T : new()
{
var sourceProperties = typeof(S).GetProperties(BindingFlags.Instance | BindingFlags.Public);
T target = new T();
foreach (var sourceProperty in sourceProperties)
{
var property = typeof(T).GetProperty(sourceProperty.Name);
if (property.PropertyType.IsPrimitive ||
property.PropertyType == typeof(string) ||
(property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
object value = sourceProperty.GetValue(source);
property.SetValue(target, value);
}
else if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
{
var sourceList = (IEnumerable)sourceProperty.GetValue(source);
if (sourceList != null)
{
var deepCopy = this.GetType().GetMethod("DeepCopy").MakeGenericMethod(sourceProperty.PropertyType.GenericTypeArguments[0], property.PropertyType.GenericTypeArguments[0]);
var ctor = property.PropertyType.GetConstructor(Type.EmptyTypes);
IList targetList = (IList) ctor.Invoke(null);
foreach (var element in sourceList)
{
targetList.Add(deepCopy.Invoke(this, new object[] { element } ));
}
property.SetValue(target, targetList);
}
}
else
{
var value = sourceProperty.GetValue(source);
if (value != null)
{
var deepCopy = this.GetType().GetMethod("DeepCopy").MakeGenericMethod(sourceProperty.PropertyType, property.PropertyType);
property.SetValue(target, deepCopy.Invoke(this, new object[] { value }));
}
}
}
return target;
}
Is it possible Deserialize unknown XML to object like below?
var xml = #"<Students><Student><Name>Arul</Name><Mark>90</Mark></Student></Students>";
var serializer = new XmlSerializer(typeof(DynamicObject));
dynamic students = serializer.Deserialize(new XmlTextReader(new StringReader(xml)));
You may want to try this.
string xml = #"<Students>
<Student ID=""100"">
<Name>Arul</Name>
<Mark>90</Mark>
</Student>
<Student>
<Name>Arul2</Name>
<Mark>80</Mark>
</Student>
</Students>";
dynamic students = DynamicXml.Parse(xml);
var id = students.Student[0].ID;
var name1 = students.Student[1].Name;
foreach(var std in students.Student)
{
Console.WriteLine(std.Mark);
}
public class DynamicXml : DynamicObject
{
XElement _root;
private DynamicXml(XElement root)
{
_root = root;
}
public static DynamicXml Parse(string xmlString)
{
return new DynamicXml(XDocument.Parse(xmlString).Root);
}
public static DynamicXml Load(string filename)
{
return new DynamicXml(XDocument.Load(filename).Root);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
var att = _root.Attribute(binder.Name);
if (att != null)
{
result = att.Value;
return true;
}
var nodes = _root.Elements(binder.Name);
if (nodes.Count() > 1)
{
result = nodes.Select(n => n.HasElements ? (object)new DynamicXml(n) : n.Value).ToList();
return true;
}
var node = _root.Element(binder.Name);
if (node != null)
{
result = node.HasElements || node.HasAttributes ? (object)new DynamicXml(node) : node.Value;
return true;
}
return true;
}
}
--EDIT--
To make it work with xml namespaces, I added RemoveNamespaces method.
public class DynamicXml : DynamicObject
{
XElement _root;
private DynamicXml(XElement root)
{
_root = root;
}
public static DynamicXml Parse(string xmlString)
{
return new DynamicXml(RemoveNamespaces(XDocument.Parse(xmlString).Root));
}
public static DynamicXml Load(string filename)
{
return new DynamicXml(RemoveNamespaces(XDocument.Load(filename).Root));
}
private static XElement RemoveNamespaces(XElement xElem)
{
var attrs = xElem.Attributes()
.Where(a => !a.IsNamespaceDeclaration)
.Select(a => new XAttribute(a.Name.LocalName, a.Value))
.ToList();
if (!xElem.HasElements)
{
XElement xElement = new XElement(xElem.Name.LocalName, attrs);
xElement.Value = xElem.Value;
return xElement;
}
var newXElem = new XElement(xElem.Name.LocalName, xElem.Elements().Select(e => RemoveNamespaces(e)));
newXElem.Add(attrs);
return newXElem;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
var att = _root.Attribute(binder.Name);
if (att != null)
{
result = att.Value;
return true;
}
var nodes = _root.Elements(binder.Name);
if (nodes.Count() > 1)
{
result = nodes.Select(n => n.HasElements ? (object)new DynamicXml(n) : n.Value).ToList();
return true;
}
var node = _root.Element(binder.Name);
if (node != null)
{
result = node.HasElements || node.HasAttributes ? (object)new DynamicXml(node) : node.Value;
return true;
}
return true;
}
}
I found that code of #RichTebb is great and it returns the Model attribute DisplayName.
But how to iterate through the all Model Display(Name=) attribute values then?
Thanks for ANY clue!
#RichTebb code
public static class HelperReflectionExtensions
{
public static string GetPropertyDisplayString<T>(Expression<Func<T, object>> propertyExpression)
{
var memberInfo = GetPropertyInformation(propertyExpression.Body);
if (memberInfo == null)
{
throw new ArgumentException(
"No property reference expression was found.",
"propertyExpression");
}
var displayAttribute = memberInfo.GetAttribute<DisplayAttribute>(false);
if (displayAttribute != null)
{
return displayAttribute.Name;
}
// ReSharper disable RedundantIfElseBlock
else
// ReSharper restore RedundantIfElseBlock
{
var displayNameAttribute = memberInfo.GetAttribute<DisplayNameAttribute>(false);
if (displayNameAttribute != null)
{
return displayNameAttribute.DisplayName;
}
// ReSharper disable RedundantIfElseBlock
else
// ReSharper restore RedundantIfElseBlock
{
return memberInfo.Name;
}
}
}
public static MemberInfo GetPropertyInformation(Expression propertyExpression)
{
Debug.Assert(propertyExpression != null, "propertyExpression != null");
var memberExpr = propertyExpression as MemberExpression;
if (memberExpr == null)
{
var unaryExpr = propertyExpression as UnaryExpression;
if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
{
memberExpr = unaryExpr.Operand as MemberExpression;
}
}
if (memberExpr != null && memberExpr.Member.MemberType == MemberTypes.Property)
{
return memberExpr.Member;
}
return null;
}
public static T GetAttribute<T>(this MemberInfo member, bool isRequired)
where T : Attribute
{
var attribute = member.GetCustomAttributes(typeof(T), false).SingleOrDefault();
if (attribute == null && isRequired)
{
throw new ArgumentException(
string.Format(
CultureInfo.InvariantCulture,
"The {0} attribute must be defined on member {1}",
typeof(T).Name,
member.Name));
}
return (T)attribute;
}
}
Sample:
string displayName = ReflectionExtensions.GetPropertyDisplayName<SomeClass>(i => i.SomeProperty);
3 hours and I found the solution.
First of all
[Display(Name = "Employed: ")]
public Nullable<bool> Employed { get; set; }
and
[DisplayName("Employed: ")]
public Nullable<bool> Employed { get; set; }
are not the same. :) For MVC we have to use this syntax [DisplayName("Employed: ")]
Also the class metadata attribute should look like
[MetadataType(typeof(PatientMetadata))]
public partial class Patient
{
....
internal sealed class PatientMetadata
{
And finally the CODE
public static class DisplayNameHelper
{
public static string GetDisplayName(object obj, string propertyName)
{
if (obj == null) return null;
return GetDisplayName(obj.GetType(), propertyName);
}
public static string GetDisplayName(Type type, string propertyName)
{
var property = type.GetProperty(propertyName);
if (property == null) return null;
return GetDisplayName(property);
}
public static string GetDisplayName(PropertyInfo property)
{
var attrName = GetAttributeDisplayName(property);
if (!string.IsNullOrEmpty(attrName))
return attrName;
var metaName = GetMetaDisplayName(property);
if (!string.IsNullOrEmpty(metaName))
return metaName;
return property.Name.ToString(CultureInfo.InvariantCulture);
}
private static string GetAttributeDisplayName(PropertyInfo property)
{
var atts = property.GetCustomAttributes(
typeof(DisplayNameAttribute), true);
if (atts.Length == 0)
return null;
var displayNameAttribute = atts[0] as DisplayNameAttribute;
return displayNameAttribute != null ? displayNameAttribute.DisplayName : null;
}
private static string GetMetaDisplayName(PropertyInfo property)
{
if (property.DeclaringType != null)
{
var atts = property.DeclaringType.GetCustomAttributes(
typeof(MetadataTypeAttribute), true);
if (atts.Length == 0)
return null;
var metaAttr = atts[0] as MetadataTypeAttribute;
if (metaAttr != null)
{
var metaProperty =
metaAttr.MetadataClassType.GetProperty(property.Name);
return metaProperty == null ? null : GetAttributeDisplayName(metaProperty);
}
}
return null;
}
}
How to use:
var t = patient.GetType();
foreach (var pi in t.GetProperties())
{
var dn = DisplayNameHelper.GetDisplayName(pi);
}
DONE!!!!
Type t = model.GetType();
foreach (PropertyInfo pi in t.GetProperties())
{
var attr = pi.GetCustomAttribute(DisplayNameAttribute, true);
if (attr != null) ...
}
I have run into a situation where I need to compare two different lists to each other and I am wondering what the best method is for doing this? I thought something like this would work but it doesn't and I can't figure out why. The Linq query is returning records it shouldn't. This is my first run at trying to figure something like this out so it is undoubtedly messy.
private static List<ColumnDefinition> FindTableStructureUpdates(List<ColumnDefinition> colDefs, List<ColumnDefinition> tblCols)
{
List<ColumnDefinition> ColsToUpdate = new List<ColumnDefinition>();
for (int i = 0; i < colDefs.Count; ++i)
{
string colDefName = colDefs[i].ColName;
string colDefDataType = colDefs[i].ColType;
string colDefAttribute = colDefs[i].ColAttributes;
var query = from tbl in tblCols
where tbl.ColName != colDefName && tbl.ColType != colDefDataType && tbl.ColAttributes != colDefAttribute
select new { colDefName, colDefDataType, colDefAttribute };
if (query.Count() > 0)
{
foreach (var item in query)
{
ColsToUpdate.Add(new ColumnDefinition(item.colDefName, item.colDefDataType, item.colDefAttribute));
}
}
}
return ColsToUpdate;
Any suggestions would be great.
Thanks.
IEquatable Implementation??
#region IEquatable<ColumnDefinition> Members
public bool Equals(ColumnDefinition other)
{
if (this.ColName.Equals(other.ColName) && this.ColType.Equals(other.ColType) && this.ColAttributes.Equals(other.ColAttributes))
return true;
return false;
}
Can't you use Enumerable.Except ?
public static IEnumerable<TSource> Except<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second
)
More details.
An example tested in Snippet Compiler
using System;
using System.Linq;
using System.Collections.Generic;
class ColumnDefinition : IEquatable<ColumnDefinition>
{
public string Name { get; set; }
public string Type { get; set; }
public string Attr { get; set; }
public ColumnDefinition()
{
Name = string.Empty;
Type = string.Empty;
Attr = string.Empty;
}
public bool Equals(ColumnDefinition other)
{
return Name.Equals(other.Name) && Type.Equals(other.Type) && Attr.Equals(other.Attr);
}
public override bool Equals(object value)
{
return (value is ColumnDefinition) ? Equals(value as ColumnDefinition) : false;
}
public override int GetHashCode()
{
return Name.GetHashCode() ^ Type.GetHashCode() ^ Attr.GetHashCode();
}
public override string ToString()
{
return string.Concat("{", Name, ":", Type, ":", Attr, "}");
}
}
public class Program
{
public static void Main(string[] args)
{
try
{
MyMain(args);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ReadKey();
}
}
public static void MyMain(string[] args)
{
var list1 = new []
{
new ColumnDefinition { Name = "foo", Type = "int", Attr = "0" },
new ColumnDefinition { Name = "bar", Type = "int", Attr = "1" },
};
var list2 = new []
{
new ColumnDefinition { Name = "foo", Type = "int", Attr = "0" },
new ColumnDefinition { Name = "bar", Type = "string", Attr = "1" },
};
foreach (var changed in Enumerable.Except(list1, list2))
{
Console.WriteLine(changed);
}
}
}