Im working with 2 List, i want to see if the main contains the same types. The 2 lists do not need to contain the same count or order, just have all of the matching Types. I know this is very possible with Linq, however i cannot use that.
private static bool ContentsMatch(List<Type> list1, List<Type> list2)
{
if (list1.Count != list2.Count)
return false;
for (int i = 0; i < list1.Count; i++)
{
if (!list1[i].Equals(list2[i]))
return false;
}
return true;
}
The above method i tried will only return true if they are in the same order.
Code for algorithm provided in the comments.
Does not depend on order or count or duplicate items. Also generic and abstracted.
bool IsSameSet<T>(IEnumerable<T> l1, IEnumerable<T> l2)
{
return IsSubSet(l1, l2) && IsSubSet(l2, l1);
}
bool IsSubSet<T>(IEnumerable<T> l1, IEnumerable<T> l2)
{
var lookup = new Dictionary<T, bool>();
foreach (var e in l1)
lookup[e] = true;
foreach (var e in l2)
if (!lookup.ContainsKey(e))
return false;
return true;
}
Usage:
Type[] l1 = { typeof(object), typeof(int), typeof(long), typeof(object) };
Type[] l2 = { typeof(int), typeof(long), typeof(object) };
var result = IsSameSet(l1, l2);
Console.WriteLine(result); // prints true
Exercise for the user:
Add an additional parameter to provide an IEqualityComparer<T> to be passed to the dictionary.
To compare any user defined customized types, we need to override Equals & GetHashCode.
Below is the code snippet you could refer to :
public class CustomizedDataType
{
private int field1;
private string field2;
public CustomizedDataType(int field1,string field2)
{
this.field1 = field1;
this.field2 = field2;
}
public override bool Equals(object obj)
{
CustomizedDataType dataType = obj as CustomizedDataType;
if (this.field1 == dataType.field1 && this.field2 == dataType.field2)
{
return true;
}
return false;
}
public override int GetHashCode()
{
return (this.field1.GetHashCode() + this.field2.GetHashCode());
}
Sample code to execute :
static void Main(string[] args)
{
//Test Data
List<CustomizedDataType> dataTypeContaineer1 = new List<CustomizedDataType>();
dataTypeContaineer1.Add(new CustomizedDataType(10,"Test10"));
dataTypeContaineer1.Add(new CustomizedDataType(11, "Test11"));
dataTypeContaineer1.Add(new CustomizedDataType(12, "Test12"));
//Test Data
List<CustomizedDataType> dataTypeContaineer2 = new List<CustomizedDataType>();
dataTypeContaineer2.Add(new CustomizedDataType(100, "Test10"));
dataTypeContaineer2.Add(new CustomizedDataType(11, "Test11"));
dataTypeContaineer2.Add(new CustomizedDataType(12, "Test120"));
//Checking if both the list contains the same types.
if (dataTypeContaineer1.GetType() == dataTypeContaineer2.GetType())
{
//Checking if both the list contains the same count
if (dataTypeContaineer1.Count == dataTypeContaineer2.Count)
{
//Checking if both the list contains the same data.
for (int index = 0; index < dataTypeContaineer1.Count; index++)
{
if(!dataTypeContaineer1[index].Equals(dataTypeContaineer2[index]))
{
Console.WriteLine("Mismatch # Index {0}", index);
}
}
}
}
}
Output :
You can use the C# keyword 'is' to see if an object is compatible with a given type.
http://msdn.microsoft.com/en-us/library/vstudio/scekt9xw.aspx
Assuming you mean that that two List<T> both have matching T, you could use:
private static Boolean MatchingBaseType(IEnumerable a, IEnumerable b)
{
return GetIListBaseType(a) == GetIListBaseType(b);
}
private static Type GetIListBaseType(IEnumerable a)
{
foreach (Type interfaceType in a.GetType().GetInterfaces())
{
if (interfaceType.IsGenericType &&
(interfaceType.GetGenericTypeDefinition() == typeof(IList<>) ||
interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
interfaceType.GetGenericTypeDefinition() == typeof(ICollection<>))
)
{
return interfaceType.GetGenericArguments()[0];
}
}
return default(Type);
}
You say count doesn't matter (though you're checking .Count()--why?) But this should return if the two lists have the same types in them.
Related
Following is a class
public class Attribute
{
public string Name { get; set; }
public string Value { get; set; }
}
Following is the code in my main method
{
var test = new List<Attribute>();
test.Add(new Attribute { Name = "Don", Value = "21" });
test.Add(new Attribute { Value = "34", Name = "Karthik" });
var test1 = new List<Attribute>();
test1.Add(new Attribute { Name = "Don", Value = "21" });
test1.Add(new Attribute { Value = "34", Name = "Karthik" });
var obj = new Program();
var areEqual1 = obj.CompareList<List<Attribute>>(test, test1);
}
I have a ComapreList method
public bool CompareList<T>(T firstList, T secondList) where T : class
{
var list1 = firstList as IList<T>;
return true;
}
Now, list1 has null. I know that .net does not allow us to do this. But is there any other way where I can cast this generic list. My purpose is to compare each property value of these two list. I am using reflection to get the property but it works only if I can convert the firstlist/secondlist to something enumerable. if I directly use the name of the class in the IList<> (firstList as IList<Attribute>) it works, but not if I give <T>. Please help.
Just create method parameterized by type of lists items type. Even more, you can create method which compares any type of collections:
public bool CompareSequences<T> (IEnumerable<T> first, IEnumerable<T> second,
Comparer<T> comparer = null)
{
comparer = comparer ?? Comparer<T>.Default;
if (first == null)
throw new ArgumentNullException(nameof(first));
if (second == null)
throw new ArgumentNullException(nameof(second));
var firstIterator = first.GetEnumerator();
var secondIterator = second.GetEnumerator();
while(true)
{
bool firstHasItem = firstIterator.MoveNext();
bool secondHasItem = secondIterator.MoveNext();
if (firstHasItem != secondHasItem)
return false;
if (!firstHasItem && !secondHasItem)
return true;
if (comparer.Compare(firstIterator.Current, secondIterator.Current) != 0)
return false;
}
}
If collection items are primitive types, you can use default comparer. But if collections contain custom items, you need either IComparable to be implemented by collection items type:
public class Attribute : IComparable<Attribute>
{
public string Name { get; set; }
public string Value { get; set; }
public int CompareTo (Attribute other)
{
int result = Name.CompareTo(other.Name);
if (result == 0)
return Value.CompareTo(other.Value);
return result;
}
}
Or you can create and pass comparer instance. You can create comparer which is using reflection to compare fields/properties of some type. But it's not as simple as you might think - properties can be complex type or collections.
Usage:
var areEqual1 = obj.CompareSequences(test, test1);
If you don't need to compare objects with complex structure (which have inner collections and other custom objects) then you can use comparer like this one:
public class SimplePropertiesComparer<T> : Comparer<T>
{
public override int Compare (T x, T y)
{
Type type = typeof(T);
var flags = BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance;
foreach (var property in type.GetProperties(flags))
{
var propertyType = property.PropertyType;
if (!typeof(IComparable).IsAssignableFrom(propertyType))
throw new NotSupportedException($"{propertyType} props are not supported.");
var propertyValueX = (IComparable)property.GetValue(x);
var propertyValueY = (IComparable)property.GetValue(y);
if (propertyValueX == null && propertyValueY == null)
continue;
if (propertyValueX == null)
return -1;
int result = propertyValueX.CompareTo(property.GetValue(y));
if (result == 0)
continue;
return result;
}
return 0;
}
}
And pass it to sequence comparer
var equal = obj.CompareSequences(test, test1, new SimplePropertiesComparer<Attribute>());
Change the signature of your method and remove the then redundant cast:
public bool CompareList<T>(IList<T> firstList, IList<T> secondList) where T : class
{
var list1 = firstList as IList<T>; // Cast is not necessary any more
return true;
}
public bool CompareGenericLists<T, U>(List<T> list1, List<U> list2)
{
try
{
if (typeof(T).Equals(typeof(U)))
{
//For checking null lists
if (list1 == null && list2 == null)
return true;
if (list1 == null || list2 == null)
throw new Exception("One of the Lists is Null");
if (list1.Count.Equals(list2.Count))
{
Type type = typeof(T);
//For primitive lists
if (type.IsPrimitive)
{
int flag = 0;
for (int i = 0; i < list1.Count; i++)
{
if (list1.ElementAt(i).Equals(list2.ElementAt(i)))
flag++;
}
if (flag != list1.Count)
throw new Exception("Objects values are not same");
}
//For Reference List
else
{
for (int i = 0; i < list1.Count; i++)
{
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
string Object1Value = string.Empty;
string Object2Value = string.Empty;
Object1Value = type.GetProperty(property.Name).GetValue(list1.ElementAt(i)).ToString();
Object2Value = type.GetProperty(property.Name).GetValue(list2.ElementAt(i)).ToString();
if (Object1Value != Object2Value)
{
throw new Exception("Objects values are not same");
}
}
}
}
}
else
throw new Exception("Length of lists is not Same");
}
else
throw new Exception("Different type of lists");
}
catch(Exception ex)
{
throw ex;
}
return true;
}
this method can be used for both primitive and reference lists.try this method.It will compare type,counts,and members of lists.
I have written a generic sort funciton to sort list and dicitonary. But LINQ doesnt works on Unity due to JIT errors. I want to have the same generics and convert it into myList.Sort() which uses CompraeTo. But Im unable to figure out how to accomplish this as generic as this.
public static List<T> MySort<T>(this List<T> source, Type typeOfObject, bool isAscending = false, params string[] param)
{
if(param.Length == 0)
return source;
if (isAscending)
{
var temp = source.OrderBy (a => (typeOfObject.GetProperty (param [0])).GetValue (a, null));
for (int i=1; i<param.Length; i++)
{
var myVar = i;
temp = temp.ThenBy((a => (typeOfObject.GetProperty(param[myVar])).GetValue (a, null)));
}
return temp.ToList();
}
else
{
var temp = source.OrderByDescending (a => (typeOfObject.GetProperty (param [0])).GetValue (a, null));
for (int i=1; i<param.Length; i++)
{
var myVar = i;
temp.ThenByDescending((a => (typeOfObject.GetProperty(param[myVar])).GetValue (a, null)));
}
return temp.ToList();
}
}
USage of this function
RealEstateItems.MySort(typeof(mIsoObjectExt), true, "UnlockLevel", "Coins", "Diamonds");
My current CompareTo Approac
myList.Sort ((a,b) => {
int result = ((a.Value) as mIsoObjectExt).UnlockLevel.CompareTo(((b.Value) as mIsoObjectExt).UnlockLevel);
// result == 0 ? result = a.Value.Coins.CompareTo(a.Value.Coins);
if(result == 0)
{
result = ((a.Value) as mIsoObjectExt).Coins.CompareTo(((b.Value) as mIsoObjectExt).Coins);
}
else
{
return result;
}
if(result == 0)
{
return ((a.Value) as mIsoObjectExt).Diamonds.CompareTo(((b.Value) as mIsoObjectExt).Diamonds);
}
return result;
});
But Im not satisfied with this i have to do this every time i have to sort even on the same properties. Basically i want to make something like above that i tell the function the type its properties to sort on and it sorts. How can i do this with Compare/CompareTo?
So we're going to need a few different building blocks to begin with. First off, what you're really doing here is sorting each item on a collection of values, as is seen in this other question. We can pull the solution from there to have a comparer for sorting items based on a collection of values:
public class SequenceComparer<T> : IComparer<IEnumerable<T>>
{
private IComparer<T> comparer;
public SequenceComparer(IComparer<T> compareer = null)
{
this.comparer = comparer ?? Comparer<T>.Default;
}
public int Compare(IEnumerable<T> x, IEnumerable<T> y)
{
using (var first = x.GetEnumerator())
using (var second = x.GetEnumerator())
{
while (true)
{
var firstHasMore = first.MoveNext();
var secondHasMore = second.MoveNext();
if (!firstHasMore && !secondHasMore)
return 0;
var lengthComparison = firstHasMore.CompareTo(secondHasMore);
if (lengthComparison != 0)
return lengthComparison;
var nextComparison = comparer.Compare(first.Current, second.Current);
if (nextComparison != 0)
return nextComparison;
}
}
}
}
We also want a way of creating a Comparison<T> delegate (which List.Sort accepts) from a projection delegate. This method is simple enough to write:
public static Comparison<T> CreateComparison<T, TKey>(Func<T, TKey> selector,
IComparer<TKey> comparer = null)
{
comparer = comparer ?? Comparer<TKey>.Default;
return (a, b) => comparer.Compare(selector(a), selector(b));
}
It'll also be useful for us to be able to reverse a Comparison<T> (to handle descending ordering):
public static Comparison<T> Reverse<T>(this Comparison<T> comparison)
{
return (a, b) => comparison(b, a);
}
Now to pull all of the pieces together. We can create a comparison that, for the projection, projects each item into a sequence of values that represent fetching each of the property names from the item using reflection. We can then reverse the comparer if we need a descending sort.
public static void MySort<T>(this List<T> source,
bool isAscending = false,
params string[] properties)
{
var type = typeof(T);
var comparison = CreateComparison((T item) =>
properties.Select(prop => type.GetProperty(prop).GetValue(item)),
new SequenceComparer<object>());
if (!isAscending)
comparison = comparison.Reverse();
source.Sort(comparison);
}
Note that if you can also use the sequence comparer to simplify the LINQ approach:
public static IEnumerable<T> MyOrdering<T>(this IEnumerable<T> source,
bool isAscending = false,
params string[] properties)
{
var type = typeof(T);
Func<T, IEnumerable<object>> selector = item =>
properties.Select(prop => type.GetProperty(prop).GetValue(item))
.ToList();
if (isAscending)
return source.OrderBy(selector, new SequenceComparer<object>());
else
return source.OrderByDescending(selector, new SequenceComparer<object>());
}
You can use Servy's approach with reflection. If you decide against reflection, you can use the below approach, but it still needs the comparison to be provided from the caller.
public class MultiValueComparer<T> : IComparer<T>
{
private IEnumerable<Comparison<T>> _comparisons;
public MultiValueComparer(IEnumerable<Comparison<T>> comparisons)
{
_comparisons = comparisons;
}
public int Compare(T x, T y)
{
foreach (var comparison in _comparisons)
{
var result = comparison(x, y);
if (result != 0)
return result;
}
return 0;
}
}
An extension method which takes a variable number of parameters
public static void Sort<T>(List<T> source, params Comparison<T>[] comparisons)
{
if (comparisons.Count() == 0)
return;
source.Sort(new MultiValueComparer<T>(comparisons));
}
Usage:
Ascending Order:
Sort(samples, (x, y) => x.Name.CompareTo(y.Name), (x, y) => x.Test.CompareTo(y.Test));
Descending Order:
Sort(samples, (x, y) => y.Name.CompareTo(x.Name), (x, y) => y.Test.CompareTo(x.Test));
Given a type, a name and a signature, how can I do a member lookup of the member with name name and signature signature using the C# rules of 7.4 (the 7.4 is the chapter number from the C# Language Specification) (or at least part of them... Let's say I can live with an exact match, without conversions/casts) at runtime? I need to get a MethodInfo/PropertyInfo/... because then I have to use it with reflection (to be more exact I'm trying to build an Expression.ForEach builder (a factory able to create an Expression Tree that represent a foreach statement), and to be pixel-perfect with the C# foreach I have to be able to do duck-typing and search for a GetEnumerator method (in the collection), a Current property and a MoveNext method (in the enumerator), as written in 8.8.4)
The problem (an example of the problem)
class C1
{
public int Current { get; set; }
public object MoveNext()
{
return null;
}
}
class C2 : C1
{
public new long Current { get; set; }
public new bool MoveNext()
{
return true;
}
}
class C3 : C2
{
}
var m = typeof(C3).GetMethods(); // I get both versions of MoveNext()
var p = typeof(C3).GetProperties(); // I get both versions of Current
Clearly if I try typeof(C3).GetProperty("Current") I get an AmbiguousMatchException exception.
A similar but different problem is present with interfaces:
interface I0
{
int Current { get; set; }
}
interface I1 : I0
{
new long Current { get; set; }
}
interface I2 : I1, I0
{
new object Current { get; set; }
}
interface I3 : I2
{
}
Here if I try to do a typeof(I3).GetProperties() I don't get the Current property (and this is something known, see for example GetProperties() to return all properties for an interface inheritance hierarchy), but I can't simply flatten the interfaces, because then I wouldn't know who is hiding who.
I know that probably this problem is solved somewhere in the Microsoft.CSharp.RuntimeBinder namespace (declared in the Microsoft.CSharp assembly). This because I'm trying to use C# rules and member lookup is necessary when you have dynamic method invocation, but I haven't been able to find anything (and then what I would get would be an Expression or perhaps a direct invocation).
After some thought it's clear that there is something similar in the Microsoft.VisualBasic assembly. VB.NET supports late binding. It's in Microsoft.VisualBasic.CompilerServices.NewLateBinding, but it doesn't expose the late bounded methods.
(note: shadowing = hiding = new in method/property/event definition in C#)
No one responded, so I'll post the code I cooked in the meantime. I hate to post 400 lines of code, but I wanted to be complete. There are two main methods: GetVisibleMethods and GetVisibleProperties. They are extension methods of the Type class. They will return the public visible (non-shadowed/non-overridden) methods/properties of a type. They should even handle VB.NET assemblies (VB.NET normally uses hide-by-name shadowing instead of hidebysig as done by C#). They cache their result in two static collections (Methods and Properties). The code is for C# 4.0, so I'm using ConcurrentDictionary<T, U>. If you are using C# 3.5 you can replace it with a Dictionary<T, U> but you have to protect it with a lock () { } when you read from it and when you write to it.
How does it works? It works by recursion (I know that recursion is normally bad, but I hope no one will create a 1.000 level inheritance chain).
For "real" types (non-interfaces) it walks upward one level (using recursion, so this one level up could go one level up and so on) and, from the returned list of methods/properties, it removes the methods/properties it's overloading/hiding.
For interfaces it's a little more complex. Type.GetInterfaces() returns all the interfaces that are inherited, ignoring if they are directly inherited or indirectly inherited. For each of those interfaces a list of declared methods/properties is calculated (through recursion). This list is paired with a list of methods/properties that are hidden by the interface (the HashSet<MethodInfo>/HashSet<PropertyInfo>). These methods/properties hidden by one interface or another are removed from all the other methods/properties returned from interfaces (so that if you have I1 with Method1(int), I2 inheriting from I1 that redeclares Method1(int) and in doing so hides I1.Method1 and I3 inheriting from I1 and I2, the fact that I2 hides I1.Method1 will be applied to the methods returned from exploring I1, so removing I1.Method1(int) (this happens because I don't generate an inheritance map for interfaces, I simply look at what hides what)).
From the returned collections of methods/properties one can use Linq to find the looked for method/property. Note that with interfaces you could find more than one method/property with a given signature. An example:
interface I1
{
void Method1();
}
interface I2
{
void Method1();
}
interface I3 : I1, I2
{
}
I3 will return two Method1().
The code:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class TypeEx
{
/// <summary>
/// Type, Tuple<Methods of type, (for interfaces)methods of base interfaces shadowed>
/// </summary>
public static readonly ConcurrentDictionary<Type, Tuple<MethodInfo[], HashSet<MethodInfo>>> Methods = new ConcurrentDictionary<Type, Tuple<MethodInfo[], HashSet<MethodInfo>>>();
/// <summary>
/// Type, Tuple<Properties of type, (for interfaces)properties of base interfaces shadowed>
/// </summary>
public static readonly ConcurrentDictionary<Type, Tuple<PropertyInfo[], HashSet<PropertyInfo>>> Properties = new ConcurrentDictionary<Type, Tuple<PropertyInfo[], HashSet<PropertyInfo>>>();
public static MethodInfo[] GetVisibleMethods(this Type type)
{
if (type.IsInterface)
{
return (MethodInfo[])type.GetVisibleMethodsInterfaceImpl().Item1.Clone();
}
return (MethodInfo[])type.GetVisibleMethodsImpl().Clone();
}
public static PropertyInfo[] GetVisibleProperties(this Type type)
{
if (type.IsInterface)
{
return (PropertyInfo[])type.GetVisiblePropertiesInterfaceImpl().Item1.Clone();
}
return (PropertyInfo[])type.GetVisiblePropertiesImpl().Clone();
}
private static MethodInfo[] GetVisibleMethodsImpl(this Type type)
{
Tuple<MethodInfo[], HashSet<MethodInfo>> tuple;
if (Methods.TryGetValue(type, out tuple))
{
return tuple.Item1;
}
var methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
if (type.BaseType == null)
{
Methods.TryAdd(type, Tuple.Create(methods, (HashSet<MethodInfo>)null));
return methods;
}
var baseMethods = type.BaseType.GetVisibleMethodsImpl().ToList();
foreach (var method in methods)
{
if (method.IsHideByName())
{
baseMethods.RemoveAll(p => p.Name == method.Name);
}
else
{
int numGenericArguments = method.GetGenericArguments().Length;
var parameters = method.GetParameters();
baseMethods.RemoveAll(p =>
{
if (!method.EqualSignature(numGenericArguments, parameters, p))
{
return false;
}
return true;
});
}
}
if (baseMethods.Count == 0)
{
Methods.TryAdd(type, Tuple.Create(methods, (HashSet<MethodInfo>)null));
return methods;
}
var methods3 = new MethodInfo[methods.Length + baseMethods.Count];
Array.Copy(methods, 0, methods3, 0, methods.Length);
baseMethods.CopyTo(methods3, methods.Length);
Methods.TryAdd(type, Tuple.Create(methods3, (HashSet<MethodInfo>)null));
return methods3;
}
private static Tuple<MethodInfo[], HashSet<MethodInfo>> GetVisibleMethodsInterfaceImpl(this Type type)
{
Tuple<MethodInfo[], HashSet<MethodInfo>> tuple;
if (Methods.TryGetValue(type, out tuple))
{
return tuple;
}
var methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
var baseInterfaces = type.GetInterfaces();
if (baseInterfaces.Length == 0)
{
tuple = Tuple.Create(methods, new HashSet<MethodInfo>());
Methods.TryAdd(type, tuple);
return tuple;
}
var baseMethods = new List<MethodInfo>();
var baseMethodsTemp = new MethodInfo[baseInterfaces.Length][];
var shadowedMethods = new HashSet<MethodInfo>();
for (int i = 0; i < baseInterfaces.Length; i++)
{
var tuple2 = baseInterfaces[i].GetVisibleMethodsInterfaceImpl();
baseMethodsTemp[i] = tuple2.Item1;
shadowedMethods.UnionWith(tuple2.Item2);
}
for (int i = 0; i < baseInterfaces.Length; i++)
{
baseMethods.AddRange(baseMethodsTemp[i].Where(p => !shadowedMethods.Contains(p)));
}
foreach (var method in methods)
{
if (method.IsHideByName())
{
baseMethods.RemoveAll(p =>
{
if (p.Name == method.Name)
{
shadowedMethods.Add(p);
return true;
}
return false;
});
}
else
{
int numGenericArguments = method.GetGenericArguments().Length;
var parameters = method.GetParameters();
baseMethods.RemoveAll(p =>
{
if (!method.EqualSignature(numGenericArguments, parameters, p))
{
return false;
}
shadowedMethods.Add(p);
return true;
});
}
}
if (baseMethods.Count == 0)
{
tuple = Tuple.Create(methods, shadowedMethods);
Methods.TryAdd(type, tuple);
return tuple;
}
var methods3 = new MethodInfo[methods.Length + baseMethods.Count];
Array.Copy(methods, 0, methods3, 0, methods.Length);
baseMethods.CopyTo(methods3, methods.Length);
tuple = Tuple.Create(methods3, shadowedMethods);
Methods.TryAdd(type, tuple);
return tuple;
}
private static PropertyInfo[] GetVisiblePropertiesImpl(this Type type)
{
Tuple<PropertyInfo[], HashSet<PropertyInfo>> tuple;
if (Properties.TryGetValue(type, out tuple))
{
return tuple.Item1;
}
var properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
if (type.BaseType == null)
{
Properties.TryAdd(type, Tuple.Create(properties, (HashSet<PropertyInfo>)null));
return properties;
}
var baseProperties = type.BaseType.GetVisiblePropertiesImpl().ToList();
foreach (var property in properties)
{
if (property.IsHideByName())
{
baseProperties.RemoveAll(p => p.Name == property.Name);
}
else
{
var indexers = property.GetIndexParameters();
baseProperties.RemoveAll(p =>
{
if (!property.EqualSignature(indexers, p))
{
return false;
}
return true;
});
}
}
if (baseProperties.Count == 0)
{
Properties.TryAdd(type, Tuple.Create(properties, (HashSet<PropertyInfo>)null));
return properties;
}
var properties3 = new PropertyInfo[properties.Length + baseProperties.Count];
Array.Copy(properties, 0, properties3, 0, properties.Length);
baseProperties.CopyTo(properties3, properties.Length);
Properties.TryAdd(type, Tuple.Create(properties3, (HashSet<PropertyInfo>)null));
return properties3;
}
private static Tuple<PropertyInfo[], HashSet<PropertyInfo>> GetVisiblePropertiesInterfaceImpl(this Type type)
{
Tuple<PropertyInfo[], HashSet<PropertyInfo>> tuple;
if (Properties.TryGetValue(type, out tuple))
{
return tuple;
}
var properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
var baseInterfaces = type.GetInterfaces();
if (baseInterfaces.Length == 0)
{
tuple = Tuple.Create(properties, new HashSet<PropertyInfo>());
Properties.TryAdd(type, tuple);
return tuple;
}
var baseProperties = new List<PropertyInfo>();
var basePropertiesTemp = new PropertyInfo[baseInterfaces.Length][];
var shadowedProperties = new HashSet<PropertyInfo>();
for (int i = 0; i < baseInterfaces.Length; i++)
{
var tuple2 = baseInterfaces[i].GetVisiblePropertiesInterfaceImpl();
basePropertiesTemp[i] = tuple2.Item1;
shadowedProperties.UnionWith(tuple2.Item2);
}
for (int i = 0; i < baseInterfaces.Length; i++)
{
baseProperties.AddRange(basePropertiesTemp[i].Where(p => !shadowedProperties.Contains(p)));
}
foreach (var property in properties)
{
if (property.IsHideByName())
{
baseProperties.RemoveAll(p =>
{
if (p.Name == property.Name)
{
shadowedProperties.Add(p);
return true;
}
return false;
});
}
else
{
var indexers = property.GetIndexParameters();
baseProperties.RemoveAll(p =>
{
if (!property.EqualSignature(indexers, p))
{
return false;
}
shadowedProperties.Add(p);
return true;
});
}
}
if (baseProperties.Count == 0)
{
tuple = Tuple.Create(properties, shadowedProperties);
Properties.TryAdd(type, tuple);
return tuple;
}
var properties3 = new PropertyInfo[properties.Length + baseProperties.Count];
Array.Copy(properties, 0, properties3, 0, properties.Length);
baseProperties.CopyTo(properties3, properties.Length);
tuple = Tuple.Create(properties3, shadowedProperties);
Properties.TryAdd(type, tuple);
return tuple;
}
private static bool EqualSignature(this MethodInfo method1, int numGenericArguments1, ParameterInfo[] parameters1, MethodInfo method2)
{
// To shadow by signature a method must have same name, same number of
// generic arguments, same number of parameters and same parameters' type
if (method1.Name != method2.Name)
{
return false;
}
if (numGenericArguments1 != method2.GetGenericArguments().Length)
{
return false;
}
var parameters2 = method2.GetParameters();
if (!parameters1.EqualParameterTypes(parameters2))
{
return false;
}
return true;
}
private static bool EqualSignature(this PropertyInfo property1, ParameterInfo[] indexers1, PropertyInfo property2)
{
// To shadow by signature a property must have same name,
// same number of indexers and same indexers' type
if (property1.Name != property2.Name)
{
return false;
}
var parameters2 = property1.GetIndexParameters();
if (!indexers1.EqualParameterTypes(parameters2))
{
return false;
}
return true;
}
private static bool EqualParameterTypes(this ParameterInfo[] parameters1, ParameterInfo[] parameters2)
{
if (parameters1.Length != parameters2.Length)
{
return false;
}
for (int i = 0; i < parameters1.Length; i++)
{
if (parameters1[i].IsOut != parameters2[i].IsOut)
{
return false;
}
if (parameters1[i].ParameterType.IsGenericParameter)
{
if (!parameters2[i].ParameterType.IsGenericParameter)
{
return false;
}
if (parameters1[i].ParameterType.GenericParameterPosition != parameters2[i].ParameterType.GenericParameterPosition)
{
return false;
}
}
else if (parameters1[i].ParameterType != parameters2[i].ParameterType)
{
return false;
}
}
return true;
}
private static bool IsHideByName(this MethodInfo method)
{
if (!method.Attributes.HasFlag(MethodAttributes.HideBySig) && (!method.Attributes.HasFlag(MethodAttributes.Virtual) || method.Attributes.HasFlag(MethodAttributes.NewSlot)))
{
return true;
}
return false;
}
private static bool IsHideByName(this PropertyInfo property)
{
var get = property.GetGetMethod();
if (get != null && get.IsHideByName())
{
return true;
}
var set = property.GetSetMethod();
if (set != null && set.IsHideByName())
{
return true;
}
return false;
}
}
Use overloaded method with BindingFlags parameter.
GetProperties(BindingFlags.DeclaredOnly)
I'm having a List of String like
List<string> MyList = new List<string>
{
"A-B",
"B-A",
"C-D",
"C-E",
"D-C",
"D-E",
"E-C",
"E-D",
"F-G",
"G-F"
};
I need to remove duplicate from the List i.e, if "A-B" and "B-A" exist then i need to keep only "A-B" (First entry)
So the result will be like
"A-B"
"C-D"
"C-E"
"D-E"
"F-G"
Is there any way to do this using LINQ?
Implement IEqualityComparer witch returns true on Equals("A-B", "B-A"). And use Enumerable.Distinct method
This returns the sequence you look for:
var result = MyList
.Select(s => s.Split('-').OrderBy(s1 => s1))
.Select(a => string.Join("-", a.ToArray()))
.Distinct();
foreach (var str in result)
{
Console.WriteLine(str);
}
In short: split each string on the - character into two-element arrays. Sort each array, and join them back together. Then you can simply use Distinct to get the unique values.
Update: when thinking a bit more, I realized that you can easily remove one of the Select calls:
var result = MyList
.Select(s => string.Join("-", s.Split('-').OrderBy(s1 => s1).ToArray()))
.Distinct();
Disclaimer: this solution will always keep the value "A-B" over "B-A", regardless of the order in which the appear in the original sequence.
You can use the Enumerable.Distinct(IEnumerable<TSource>, IEqualityComparer<TSource>) overload.
Now you just need to implement IEqualityComparer. Here's something for you to get started:
class Comparer : IEqualityComparer<String>
{
public bool Equals(String s1, String s2)
{
// will need to test for nullity
return Reverse(s1).Equals(s2);
}
public int GetHashCode(String s)
{
// will have to implement this
}
}
For a Reverse() implementation, see this question
You need to implement the IEqualityComparer like this:
public class CharComparer : IEqualityComparer<string>
{
#region IEqualityComparer<string> Members
public bool Equals(string x, string y)
{
if (x == y)
return true;
if (x.Length == 3 && y.Length == 3)
{
if (x[2] == y[0] && x[0] == y[2])
return true;
if (x[0] == y[2] && x[2] == y[0])
return true;
}
return false;
}
public int GetHashCode(string obj)
{
// return 0 to force the Equals to fire (otherwise it won't...!)
return 0;
}
#endregion
}
The sample program:
class Program
{
static void Main(string[] args)
{
List<string> MyList = new List<string>
{
"A-B",
"B-A",
"C-D",
"C-E",
"D-C",
"D-E",
"E-C",
"E-D",
"F-G",
"G-F"
};
var distinct = MyList.Distinct(new CharComparer());
foreach (string s in distinct)
Console.WriteLine(s);
Console.ReadLine();
}
}
The result:
"A-B"
"C-D"
"C-E"
"D-E"
"F-G"
Very basic, but could be written better (but it's just working):
class Comparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return (x[0] == y[0] && x[2] == y[2]) || (x[0] == y[2] && x[2] == y[0]);
}
public int GetHashCode(string obj)
{
return 0;
}
}
var MyList = new List<String>
{
"A-B",
"B-A",
"C-D",
"C-E",
"D-C",
"D-E",
"E-C",
"E-D",
"F-G",
"G-F"
}
.Distinct(new Comparer());
foreach (var s in MyList)
{
Console.WriteLine(s);
}
int checkID = 0;
while (checkID < MyList.Count)
{
string szCheckItem = MyList[checkID];
string []Pairs = szCheckItem.Split("-".ToCharArray());
string szInvertItem = Pairs[1] + "-" + Pairs[0];
int i=checkID+1;
while (i < MyList.Count)
{
if((MyList[i] == szCheckItem) || (MyList[i] == szInvertItem))
{
MyList.RemoveAt(i);
continue;
}
i++;
}
checkID++;
}
I am writing a Clone method using reflection. How do I detect that a property is an indexed property using reflection? For example:
public string[] Items
{
get;
set;
}
My method so far:
public static T Clone<T>(T from, List<string> propertiesToIgnore) where T : new()
{
T to = new T();
Type myType = from.GetType();
PropertyInfo[] myProperties = myType.GetProperties();
for (int i = 0; i < myProperties.Length; i++)
{
if (myProperties[i].CanWrite && !propertiesToIgnore.Contains(myProperties[i].Name))
{
myProperties[i].SetValue(to,myProperties[i].GetValue(from,null),null);
}
}
return to;
}
if (propertyInfo.GetIndexParameters().Length > 0)
{
// Property is an indexer
}
Sorry, but
public string[] Items { get; set; }
is not an indexed property, it's merely of an array type!
However the following is:
public string this[int index]
{
get { ... }
set { ... }
}
What you want is the GetIndexParameters() method. If the array that it returns has more than 0 items, that means it's an indexed property.
See the MSDN documentation for more details.
If you call property.GetValue(obj,null), and the property IS indexed, then you will get a parameter count mismatch exception. Better to check whether the property is indexed using GetIndexParameters() and then decide what to do.
Here is some code that worked for me:
foreach (PropertyInfo property in obj.GetType().GetProperties())
{
object value = property.GetValue(obj, null);
if (value is object[])
{
....
}
}
P.S. .GetIndexParameters().Length > 0) works for the case described in this article: http://msdn.microsoft.com/en-us/library/b05d59ty.aspx
So if you care about the property named Chars for a value of type string, use that, but it does not work for most of the arrays I was interested in, including, I am pretty sure, a string array from the original question.
You can convert the indexer to IEnumerable
public static IEnumerable<T> AsEnumerable<T>(this object o) where T : class {
var list = new List<T>();
System.Reflection.PropertyInfo indexerProperty = null;
foreach (System.Reflection.PropertyInfo pi in o.GetType().GetProperties()) {
if (pi.GetIndexParameters().Length > 0) {
indexerProperty = pi;
break;
}
}
if (indexerProperty.IsNotNull()) {
var len = o.GetPropertyValue<int>("Length");
for (int i = 0; i < len; i++) {
var item = indexerProperty.GetValue(o, new object[]{i});
if (item.IsNotNull()) {
var itemObject = item as T;
if (itemObject.IsNotNull()) {
list.Add(itemObject);
}
}
}
}
return list;
}
public static bool IsNotNull(this object o) {
return o != null;
}
public static T GetPropertyValue<T>(this object source, string property) {
if (source == null)
throw new ArgumentNullException("source");
var sourceType = source.GetType();
var sourceProperties = sourceType.GetProperties();
var properties = sourceProperties
.Where(s => s.Name.Equals(property));
if (properties.Count() == 0) {
sourceProperties = sourceType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic);
properties = sourceProperties.Where(s => s.Name.Equals(property));
}
if (properties.Count() > 0) {
var propertyValue = properties
.Select(s => s.GetValue(source, null))
.FirstOrDefault();
return propertyValue != null ? (T)propertyValue : default(T);
}
return default(T);
}