Checking values of objects from root to desired child - c#

So i have an object filled with many inner objects. To get a value of inner object that i want to know i must first check if all parents all the way to root object are not null. Code looks like this:
StringBuilder stringBuilder = new StringBuilder();
//Wanted object can be even deeper
if (root != null &&
root.InnerObject1 != null &&
root.InnerObject1.InnerObject2 != null &&
root.InnerObject1.InnerObject2.InnerObject3 != null &&
root.InnerObject1.InnerObject2.InnerObject3.value != null)
{
stringBuilder.Append(root.InnerObject1.InnerObject2.InnerObject3.value)
}
Can this be done in more elegant way?

With current C# version: no.
With the next one: yes.
C# 6 will have a new feature called null-conditional operator designed for cases like this. It will let you write
var value = root?.InnerObject2?.InnerObject2?.InnerObject3?.value;
if(value != null)
stringBuilder.Append(value);

Why not introduce:
private static bool NestedElementAvailable(Node startNode, int depth)
{
Node node = startNode
while(node != null && depth > 0)
{
node = node.InnerNode;
depth--;
}
return depth == 0 && node != null && node.Value != null;
}
Edit:
private static bool SomeSeriousNameForCondition(Node node)
{
return //the condition
}
Then in the orignial code
if(SomeSeriousNameForCondition(root))
I know this does not reduce the code but at least its more readable.

Consider this:
class Program
{
static void Main(string[] args)
{
Test root = new Test
{
Property1 = new Test { Value = 3 },
Property2 = new Test { Value = 4 },
Property3 = new Test { Property1 = new Test { Value = 4} }
};
int testValue1;
if (root.TryGetData<int>(out testValue1,"Property1","Value"))
{
Console.WriteLine(testValue1);
}
int testValue2;
if (root.TryGetData<int>(out testValue2, "Property2","Property1","Value" ))
{
Console.WriteLine("Would be bad if this would enter here");
}
if (root.TryGetData<int>(out testValue2, "Property3", "Property1", "Value"))
{
Console.WriteLine(testValue2);
}
}
}
class Test
{
public Test Property1 { get; set; }
public Test Property2 { get; set; }
public Test Property3 { get; set; }
public int Value { get; set; }
}
public static class ExtensionMethods
{
public static bool TryGetData<T>(this object theObject, out T value, params string[] path)
{
object cursor = theObject;
for (int i = 0; i < path.Length; i++)
{
if (cursor == null)
{
value = default(T);
return false;
}
Type t = cursor.GetType();
cursor = t.GetProperty(path[i]).GetValue(cursor);
}
value = (T)cursor;
return true;
}
}
It's by no means good practise but it would get the job done.

Related

Preexisting Serializer to [FromQuery] format

I want to consume an ASP.NET Core Web API method that includes [FromQuery] parameters.
Since the format is somewhat unusual, I figured there would exist a library function that would take a complex type and generate the query string formatted text - however, I can't find one.
IOW, given a controller method defined like this:
[HttpGet("testing")]
public bool Testing([FromQuery]X x)
{
return (x?.Ys[1]?.Zs[1]?.Bs[3] == 3 && x?.Ys[1]?.Zs[0]?.A == 4);
}
And an X defined like this:
public class X
{
public Y[] Ys { get; set; }
}
public class Y
{
public Z[] Zs { get; set; }
}
public class Z
{
public int A { get; set; }
public int[] Bs { get; set; }
}
First of all, what's an example of what ASP.NET [FromQuery] is expecting to encounter in the query string in order to return true?
Secondly, is there a function somewhere that can serialize an object appropriately into whatever ASP.NET is expecting, or do I need to write one?
You can use the following "serializer"
public class QueryStringSerializer
{
private static bool IsPrimitive(object obj)
{
return obj.GetType().IsPrimitive || obj is string || obj is Guid;
}
private static bool IsEnumerable(object obj)
{
return obj is IEnumerable && !IsPrimitive(obj);
}
private static bool IsComplex(object obj)
{
return !(obj is IEnumerable) && !IsPrimitive(obj);
}
private static StringBuilder ToQueryStringInternal(object obj, string prop = null)
{
StringBuilder queryString = new StringBuilder();
//skip null values
if (obj == null)
return queryString;
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
if (IsEnumerable(obj))
{
int i = 0;
foreach (object item in obj as IEnumerable)
{
string query = ToQueryStringInternal(item, $"{prop}[{i}]").ToString();
queryString.Append(query);
i++;
}
}
else if (IsComplex(obj))
{
foreach (PropertyInfo property in properties)
{
string propName = property.Name;
object value = property.GetValue(obj);
string name = prop == null ? propName : $"{prop}.{propName}";
string query = ToQueryStringInternal(value, name).ToString();
queryString.Append(query);
}
}
else
{
string encoded = HttpUtility.UrlEncode(Convert.ToString(obj));
queryString.Append($"{prop}={encoded}&");
}
return queryString;
}
public static string ToQueryString(object obj, string propertyName = null)
{
StringBuilder queryString = ToQueryStringInternal(obj, propertyName);
queryString.Length--;
return queryString.ToString();
}
}
Usage
var x = new X
{
Ys = new Y[] {
new Y {
Zs = new Z[] { new Z { } }
},
new Y {
Zs = new Z[] {
new Z { },
new Z {
A = 1,
Bs = new int[] { 0, 1, 2, 3 }
}
}
}
}
};
string query = QueryStringSerializer.ToQueryString(x);
Result
Ys[0].Zs[0].A=0&Ys[1].Zs[0].A=0&Ys[1].Zs[1].A=1&Ys[1].Zs[1].Bs[0]=0&Ys[1].Zs[1].Bs[1]=1&Ys[1].Zs[1].Bs[2]=2&Ys[1].Zs[1].Bs[3]=3
Caution
The serializer may still contain various bags. Also, do not create array with "gaps" such as
var q = new X[] {
new X { },
null, //a gap
new X { }
};
The result will be technically correct but ASP.NET model binder will bind only the first element properly.

Get Values From Complex Class Using Reflection

I have a class, which is created and populated from an xml string, I've simplified it for example purposes:
[XmlRoot("Person")]
public sealed class Person
{
[XmlElement("Name")]
public string Name { get; set; }
[XmlElement("Location")]
public string Location { get; set; }
[XmlElement("Emails", Type = typeof(PersonEmails)]
public PersonEmails Emails { get; set; }
}
public class PersonEmails
{
[XmlElement("Email", Type = typeof(PersonEmail))]
public PersonEmail[] Emails { get; set; }
}
public class PersonEmail
{
[XmlAttribute("Type")]
public string Type { get; set; }
[XmlText]
public string Value { get; set; }
}
To extract the information, I'm trying to load them into another class, which is simply:
public class TransferObject
{
public string Name { get; set; }
public ObjectField[] Fields { get; set; }
}
public class ObjectField
{
public string Name { get; set; }
public string Value { get; set; }
}
I'm only populating "Fields" from the other object, which would simply be (Name = "Location", Value = "London"), but for Emails, (Name = "Email"+Type, Value = jeff#here.com)
Currently I can populate all the other fields, but I'm stuck with Emails, and knowing how to dig deep enough to be able to use reflection (or not) to get the information I need. Currently I'm using:
Person person = Person.FromXmlString(xmlString);
List<ObjectField> fields = new List<ObjectField>();
foreach (PropertyInfo pinfo in person.getType().GetProperties()
{
fields.Add(new ObjectField { Name = pinfo.Name, Value = pinfo.getValue(person, null).ToString();
}
How can I expand on the above to add all my emails to the list?
You are trying to type cast a complex values type to string value so you lost the data. Instead use following code:
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Name = "Person One";
person.Location = "India";
person.Emails = new PersonEmails();
person.Phones = new PersonPhones();
person.Emails.Emails = new PersonEmail[] { new PersonEmail() { Type = "Official", Value = "xyz#official.com" }, new PersonEmail() { Type = "Personal", Value = "xyz#personal.com" } };
person.Phones.Phones = new PersonPhone[] { new PersonPhone() { Type = "Official", Value = "789-456-1230" }, new PersonPhone() { Type = "Personal", Value = "123-456-7890" } };
List<ObjectField> fields = new List<ObjectField>();
fields = GetPropertyValues(person);
}
static List<ObjectField> GetPropertyValues(object obj)
{
List<ObjectField> propList = new List<ObjectField>();
foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
{
var value = pinfo.GetValue(obj, null);
if (pinfo.PropertyType.IsArray)
{
var arr = value as object[];
for (var i = 0; i < arr.Length; i++)
{
if (arr[i].GetType().IsPrimitive)
{
propList.Add(new ObjectField() { Name = pinfo.Name + i.ToString(), Value = arr[i].ToString() });
}
else
{
var lst = GetPropertyValues(arr[i]);
if (lst != null && lst.Count > 0)
propList.AddRange(lst);
}
}
}
else
{
if (pinfo.PropertyType.IsPrimitive || value.GetType() == typeof(string))
{
propList.Add(new ObjectField() { Name = pinfo.Name, Value = value.ToString() });
}
else
{
var lst = GetPropertyValues(value);
if (lst != null && lst.Count > 0)
propList.AddRange(lst);
}
}
}
return propList;
}
}
Check this snippet out:
if(pinfo.PropertyType.IsArray)
{
// Grab the actual instance of the array.
// We'll have to use it in a few spots.
var array = pinfo.GetValue(personObject);
// Get the length of the array and build an indexArray.
int length = (int)pinfo.PropertyType.GetProperty("Length").GetValue(array);
// Get the "GetValue" method so we can extact the array values
var getValue = findGetValue(pinfo.PropertyType);
// Cycle through each index and use our "getValue" to fetch the value from the array.
for(int i=0; i<length; i++)
fields.Add(new ObjectField { Name = pinfo.Name, Value = getValue.Invoke(array, new object[]{i}).ToString();
}
// Looks for the "GetValue(int index)" MethodInfo.
private static System.Reflection.MethodInfo findGetValue(Type t)
{
return (from mi in t.GetMethods()
where mi.Name == "GetValue"
let parms = mi.GetParameters()
where parms.Length == 1
from p in parms
where p.ParameterType == typeof(int)
select mi).First();
}
You can definately do it with Reflection... You can take advantage of the fact that a Type can tell you if it's an array or not (IsArray)... and then take advantage of the fact that an Array has a method GetValue(int index) that will give you a value back.
Per your comment
Because Emails is a property within a different class, recursion should be used. However the trick is knowing when to go to the next level. Really that is up to you, but
if it were me, I would use some sort of Attribute:
static void fetchProperties(Object instance, List<ObjectField> fields)
{
foreach(var pinfo in instance.GetType().GetProperties())
{
if(pinfo.PropertyType.IsArray)
{
... // Code described above
}
else if(pinfo.PropertyType.GetCustomAttributes(typeof(SomeAttribute), false).Any())
// Go the next level
fetchProperties(pinfo.GetValue(instance), fields);
else
{
... // Do normal code
}
}
}

C# Parse IF-ELSE Statement

UPDATE
I don´t want you to do my Work and write code for me I just wanted a nurge in the right Direction!
So I have to be more specific with my Problem, give me a chance to do some work on this and I will update my question with the results ;-)
UPDATE 2
I´ve solved my Problem with Roslyn maybe not very elegant but it work for my needs, here is the code ;-)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
namespace ParserTest
{
public class MyParser
{
private int _currentLevel = 1;
public void TestMethod()
{
string testString =
#" if(#ISEMPTY(temp.tis_filterstatus2))
{
tis_datasheet_selection.is_selected = 'Y'
}
else
{
if(#ISEMPTY(temp.tis_programmtyp_filter)) { }
else
{
AND tis_programme_v.type = '#SUB(temp.tis_programmtyp_filter)'
}
if(#ISEMPTY(temp.tis_programmfilter)) { }
else
{
AND tis_programme_v.programm LIKE '#SUB(temp.tis_programmfilter)%'
}";
var result = this.Parse(testString);
var finalResult = this.GenerateDsl(result);
}
public List<IfStatement> Parse(string strToParse)
{
var result = new List<IfStatement>();
var syntaxTree = SyntaxTree.ParseText(#"using System;class C{static void M(){" + strToParse + "}}");
var rootNodes = syntaxTree.GetRoot().DescendantNodes().Where(getRootNodes);
result = rootNodes.Select(n => ToIfStatement(n, null)).ToList();
ApplyNestingLevel(result);
return result;
}
private string GenerateDsl(List<IfStatement> list)
{
var sb = new StringBuilder();
foreach(var ifStmt in list)
{
IfStatementToDsl(ifStmt, sb);
}
return sb.ToString();
}
private string IfStatementToDsl(IfStatement ifStmt, StringBuilder sb)
{
string sqr = "";
for (int i = 0; i < ifStmt.Level; i++)
{
sqr += "'";
}
sb.Append("#IF(");
sb.Append(ifStmt.Condition.ApplyLevel(ifStmt.Level) + "," + sqr);
sb.Append(ifStmt.Statement.ApplyLevel(ifStmt.Level));
if(ifStmt.Childs.Count > 0)
{
foreach(var c in ifStmt.Childs)
{
IfStatementToDsl(c, sb);
}
}
sb.Append(sqr + "," + sqr);
if(ifStmt.Else != null)
{
sb.Append(ifStmt.Else.Statement.ApplyLevel(ifStmt.Level));
foreach(var c in ifStmt.Else.Childs)
{
IfStatementToDsl(c, sb);
}
}
sb.Append(sqr + ")");
return sb.ToString();
}
#region Parsing-Methods
private IfStatement ToIfStatement(SyntaxNode node, SyntaxNode parent)
{
var ifNode = (IfStatementSyntax)node;
var ifStmt = new IfStatement
{
Condition = ifNode.Condition.ToString(),
Statement = GetIfStatement(ifNode),
Childs = GetIfChilds(ifNode)
};
if (ifNode.Else != null)
{
ifStmt.Else = new ElseStatement
{
Statement = GetElseStatement(ifNode.Else),
Childs = GetElseChilds(ifNode.Else)
};
}
return ifStmt;
}
private List<IfStatement> GetIfChilds(IfStatementSyntax node)
{
var childs = node.Statement.DescendantNodes().Where(n => WhereIfNodes(n, node));
return childs.Select(n => ToIfStatement(n, node)).ToList();
}
private List<IfStatement> GetElseChilds(ElseClauseSyntax node)
{
var childs = node.Statement.DescendantNodes().Where(n => WhereElseNodes(n, node));
return childs.Select(n => ToIfStatement(n, node)).ToList();
}
private string GetIfStatement(IfStatementSyntax node)
{
var result = node.Statement.DescendantNodes().Where(n => WhereIfStatement(n, node));
string returnValue = "";
foreach (var n in result)
{
returnValue += n.ToString();
}
return returnValue.CleanString();
}
private string GetElseStatement(ElseClauseSyntax node)
{
var result = node.Statement.DescendantNodes().Where(n => WhereElseStatement(n, node));
string returnValue = "";
foreach (var n in result)
{
returnValue += n.ToString() + " ";
}
return returnValue.CleanString();
}
private void ApplyNestingLevel(List<IfStatement> list)
{
foreach (var item in list)
{
item.Level = _currentLevel;
if (item.Childs.Count > 0 || (item.Else != null && item.Else.Childs.Count > 0))
{
_currentLevel++;
}
ApplyNestingLevel(item.Childs);
if (item.Else != null)
{
ApplyNestingLevel(item.Else.Childs);
}
}
}
#endregion
#region Linq Where-Conditions
private bool WhereIfNodes(SyntaxNode node, IfStatementSyntax parent)
{
if(node.Kind == SyntaxKind.IfStatement && (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private bool WhereElseNodes(SyntaxNode node, ElseClauseSyntax parent)
{
if (node.Kind == SyntaxKind.IfStatement && (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private bool WhereIfStatement(SyntaxNode node, IfStatementSyntax parent)
{
if ((node.Kind == SyntaxKind.ExpressionStatement || node.Kind == SyntaxKind.LocalDeclarationStatement)
&& (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private bool WhereElseStatement(SyntaxNode node, ElseClauseSyntax parent)
{
if ((node.Kind == SyntaxKind.ExpressionStatement || node.Kind == SyntaxKind.LocalDeclarationStatement)
&& (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private Func<SyntaxNode, bool> getRootNodes =
n => n.Kind == SyntaxKind.IfStatement &&
(n.Parent.Parent.Kind != SyntaxKind.ElseClause && n.Parent.Parent.Kind != SyntaxKind.IfStatement);
#endregion
}
public class IfStatement
{
public int Level { get; set; }
public string Condition { get; set; }
public string Statement { get; set; }
public ElseStatement Else { get; set; }
public List<IfStatement> Childs { get; set; }
}
public class ElseStatement
{
public string Statement { get; set; }
public List<IfStatement> Childs { get; set; }
}
public static class Ext
{
public static string CleanString(this string value)
{
return value.Replace("\t", "").Replace("\n", "").Replace("\r", "");
}
public static string ApplyLevel(this string value, int level)
{
int multiplier = level * 2;
if (level == 0)
multiplier = 1;
var sb = new StringBuilder(multiplier);
for (int i = 0; i < multiplier; i++)
{
sb.Append("'");
}
return value.Replace("'", sb.ToString());
}
}
}
I have to write if-else Statements in a Domain-Specific-Language which is really a pain in the ass!
(The DSL is from a Third-Party-Tool which I have to use to generate WHERE-Statements for SQL-Queries)
Syntax:
#IF(#ISEMPTY(#SUB(temp.last_name))),'if true','else')
#SUB() reads a textboxvalue
Sample:
#IF(#ISEMPTY(#SUB(temp.last_name))),'','account_contact.last_name = ''DOE'' ')
you have to double your single-quotes in the else statement and if you want to nest different "if-else" every time you go a level deeper you have to double the doubled single-quotes!
You see it´s not very simple to write if you have complicated contitions...
So I thought I write a parser that transforms a normal if-else statement to this DSL-Syntax!
The Parser should create objects of this class:
public class IfCondition
{
public int ID { get; set; }
public int ParentID { get; set; }
public int Level { get; set; }
public string Condition { get; set; }
public string Content { get; set; }
public string ElseContent { get; set; }
}
based on a Collection of this Objects I could generate the DSL-Statements!
So my Problem is I really don´t have a clue, how to parse a String like this:
IF(#ISEMPTY(#SUB(temp.last_name))) { }
ELSE
{
IF(#SUB(temp.test) = 'Y')
{
account_contact.last_name = 'DOE'
}
ELSE
{
account_contat.first_name = "JOHN"
}
}
can somebody give me a nudge in the right direction?
If you use Roslyn for syntax rewritting. Not to just write about what you can do, here is an easy example.
Basically how it works. You create a syntax tree for your code and then use predefined visitors to visit those nodes you want to rewrite, you replace them by valid C# code and then you can compile this tree and make it work.
EDIT:
Another, more reliable source with an example

Comparing two objects and returning the differences

I have to run comparisons between thousands of pairs of objects, and then perform actions depending on the differences.
Is there an "accepted" way of doing this?
class ObjectA
{
public string FieldA { get; set; }
public string FieldB { get; set; }
public string FieldC { get; set; }
}
class ObjectB
{
public string FieldA { get; set; }
public string FieldB { get; set; }
public string FieldC { get; set; }
public bool Equals(ObjectA obj)
{
if ((object)obj == null) return false;
if (this.FieldA != obj.FieldA) return false;
if (this.FieldB != obj.FieldB) return false;
if (this.FieldC != obj.FieldC) return false;
return true;
}
}
void test()
{
ObjectA a = new ObjectA();
ObjectB b = new ObjectB();
if (b.Equals(a))
{
Console.WriteLine("Same!!");
}
}
That does a fairly simple test to determine if b=a, but I also want to know what is different between them.
Should I add a differences() method that returns a list of properties? That seems a bit not.net though, as then I'll be bandying about strings.
public List<string> Differences(ObjectA obj)
{
List<string> differences = new List<string>();
if ((object)obj == null)
{
differences.Add("null");
}
else
{
if (this.FieldA != obj.FieldA) differences.Add("FieldA");
if (this.FieldB != obj.FieldB) differences.Add("FieldB");
if (this.FieldC != obj.FieldC) differences.Add("FieldC");
}
return differences;
}
Also that seems much slower than the first, as I would be creating all those List<string>, and not short-cutting the comparisons. Or is that just the price I pay for having the extra information?
Maybe you should try this:
http://comparenetobjects.codeplex.com/
All credit to the author...
Edit: Since codeplex is shutting down, the github url : https://github.com/GregFinzer/Compare-Net-Objects
There is nothing built in that will allow you to represent partial objects (i.e the differences).
Your approach seems reasonable for what you are trying to achieve.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
class ObjectA
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public DateTime PropertyD { get; set; }
public string FieldA;
public DateTime FieldB;
}
class ObjectB
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public DateTime PropertyD { get; set; }
public string FieldA;
public DateTime FieldB;
}
class Program
{
static void Main(string[] args)
{
// create two objects with same properties
ObjectA a = new ObjectA() { PropertyA = "test", PropertyB = "test2", PropertyC = "test3" };
ObjectB b = new ObjectB() { PropertyA = "test", PropertyB = "test2", PropertyC = "test3" };
// add fields to those objects
a.FieldA = "hello";
b.FieldA = "Something differnt";
if (a.ComparePropertiesTo(b))
{
Console.WriteLine("objects have the same properties");
}
else
{
Console.WriteLine("objects have diferent properties!");
}
if (a.CompareFieldsTo(b))
{
Console.WriteLine("objects have the same Fields");
}
else
{
Console.WriteLine("objects have diferent Fields!");
}
Console.Read();
}
}
public static class Utilities
{
public static bool ComparePropertiesTo(this Object a, Object b)
{
System.Reflection.PropertyInfo[] properties = a.GetType().GetProperties(); // get all the properties of object a
foreach (var property in properties)
{
var propertyName = property.Name;
var aValue = a.GetType().GetProperty(propertyName).GetValue(a, null);
object bValue;
try // try to get the same property from object b. maybe that property does
// not exist!
{
bValue = b.GetType().GetProperty(propertyName).GetValue(b, null);
}
catch
{
return false;
}
if (aValue == null && bValue == null)
continue;
if (aValue == null && bValue != null)
return false;
if (aValue != null && bValue == null)
return false;
// if properties do not match return false
if (aValue.GetHashCode() != bValue.GetHashCode())
{
return false;
}
}
return true;
}
public static bool CompareFieldsTo(this Object a, Object b)
{
System.Reflection.FieldInfo[] fields = a.GetType().GetFields(); // get all the properties of object a
foreach (var field in fields)
{
var fieldName = field.Name;
var aValue = a.GetType().GetField(fieldName).GetValue(a);
object bValue;
try // try to get the same property from object b. maybe that property does
// not exist!
{
bValue = b.GetType().GetField(fieldName).GetValue(b);
}
catch
{
return false;
}
if (aValue == null && bValue == null)
continue;
if (aValue == null && bValue != null)
return false;
if (aValue != null && bValue == null)
return false;
// if properties do not match return false
if (aValue.GetHashCode() != bValue.GetHashCode())
{
return false;
}
}
return true;
}
}
As long as the names of the properties are equal, you can do this using the property map of each object and linq. I've done this in the past, but I don't have the code in front of me at the moment, sorry.
Here's an example I used for unit testing two instances of the same object type. I was testing to ensure that the properties that were serialized to file and populated in a new instance of the same object type were the same. Note that this is using System.Reflection and that you are comparing instances of the same type.
//Assume yourobjectA and yourobjectB have already been instantiated and populated.
//loop throught he properties and compare
//they should all be set the same as the previous instance
PropertyInfo[] propertiesA = yourobjectA.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] propertiesB = yourobjectB.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
int count = oldProperties.Length;
for (int i = 0; i < count; i++)
{
if ((propertiesA [i].CanRead) && (propertiesB [i].CanRead))
{
if (propertiesA [i].PropertyType == typeof(String))
{
object oldStringValue = (string)propertiesA[i].GetValue(yourobjectA, null);
object newStringValue = (string)propertiesB[i].GetValue(yourobjectB., null);
if(oldStringValue != newStringValue )
{
//Do something
}
}
if (propertiesA [i].PropertyType == typeof(Boolean))
{
object oldBoolValue = (bool)propertiesA [i].GetValue(yourobjectA, null);
object newBoolValue = (bool)propertiesB [i].GetValue(yourobjectB., null);
if(oldBoolValue != newBoolValue)
{
//Do something
}
}
}
}

C# Comparing Two Custom Lists

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

Categories