Generalize Method to 'Get' Any Object Property - c#

Say I have a Dictionary object which contains many instances of an object called SomeObject and each SomeObject has properties named Property1 and Property2. Now say I have a method which can return a new Dictionary sorted by Property1. However, I'd like to generalize that method such that I can tell it which property to sort by.
For example, to do this, I know I could easily have two separate methods such as:
public Dictionary<string, SomeObject> SortByProp1(Dictionary<string, SomeObject> dict) { ... }
public Dictionary<string, SomeObject> SortByProp2(Dictionary<string, SomeObject> dict) { ... }
But, I'm wondering if it's possible to combine these into one method in which I can give a parameter to identify which method to return? I don't know of a way to generalize a property like that...
Note: I do realize I could always use something like an if-statement which could be based on a string of the property name, but that doesn't seem like a very elegant, acceptable answer much better than just having two separate methods to begin with.

The method you seek is built into the IEnumerable<T> interface, and is OrderBy, though it might not work out as smothly for a Dictionary as you might like.
Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>, so its OrderBy method takes a lambda expression which itself takes a KeyValuePair<TKey, TValue>, and returns a selector method that describes what you're sorting by.
For example, if you have Dictionary<int, Customer>, this will return to you an IEnumerable<KeyValuePair<int, Customer>> sorted by customer name:
myDict.OrderBy(kvp => kvp.Value.Name);
Then to get just the customers themselves in this sorted order, you'd say:
IEnumerable<Customer> orderedByName = myDict.OrderBy(kvp => kvp.Value.Name).Select(kvp => kvp.Value);

Can you try adding a generic type parameter, for the ordering key - and accept a predicate for the ordering?
Such as:
public Dictionary<string, SomeObject> SortByProp<TProp>(Dictionary<string, SomeObject> dict, Expression<SomeObject,TProp> orderPredicate)
{
return dict.OrderBy(orderPredicate);
}
// Usage:
SortByProp(apples, x => x.AppleColor);
SortByProp(oranges, x => x.OrangeType);

You can accept a delegate to select the property:
public Dictionary<string, SomeObject> Sort<TProperty>(Dictionary<string, SomeObject> dict, Func<SomeObject, TProperty> selector) { ... }
You can call it like this:
var sortedDict = Sort(dict, o => o.Property1);

Related

How to pass search parameter, into function that will search a c# collection

Assume I have a collection of the form:
List<Member> myMembers= new List<Member>()
{
new Member(){ID=1,FirstName="John",LastName="Doe"},
new Member(){ID=3,FirstName="Allan",LastName="Jones"},
new Member(){ID=2,FirstName="Martin",LastName="Moe"},
new Member(){ID=4,FirstName="Ludwig",LastName="Issac"}
};
I can sort this list via FirstName by using:
myMembers.Sort((x, y) => x.FirstName.CompareTo(y.FirstName));
I would like to do this inside of a function, so that I can pass the desired search parameter. Something like:
public void sortCollection( parameter SearchTerm, List<Member> myCollection )
{
myCollection ((x, y) => x.SearchTerm.CompareTo(y.FirstName));
}
Obviously here, I cannot pass in the desired search field this way, but is it possible to do what I am asking?
You can create a generic extension method for that and pass Func<T, TResult> delegate to it, which is used as key selector for built-in Sort method
public static void SortExt<T, TValue>(this List<T> collection, Func<T, TValue> selector)
{
var comparer = Comparer<TValue>.Default;
collection.Sort((x, y) => comparer.Compare(selector(x), selector(y)));
}
Keep in mind that you should compare the same fields of compared objects.
Example of the usage
myMembers.SortExt(member => member.FirstName);
If you want to compare the myMembers collection only, the declaration can be simplified
public static void SortExt<TValue>(this List<Member> members, Func<Member, TValue> selector)
{
var comparer = Comparer<TValue>.Default;
members.Sort((x, y) => comparer.Compare(selector(x), selector(y)));
}
Another option is to introduce a Comparison<T> delegate instance to store the logic of field comparison and pass it to the Sort method. Here you can specify any custom comparison that you want
Comparison<Member> comparison = (x, y) => x.FirstName.CompareTo(y.FirstName);
myMembers.Sort(comparison);
Demo on dotnet fiddle
It seems to me that you can use Func<> to be able to dynamic order by.
var result = sortCollection(p => p.ID, myMembers);
public static IEnumerable<Member> sortCollection(Func<Member, object> keySelector, List<Member> myCollection)
{
return myCollection.OrderBy(keySelector);
}
Read the following post to have a better understanding
Dynamic Order By in Linq
Instead of writing one more wrapper on Linq .OrderBy() or .Sort() method and calling that where ever you want to sort, use Linq OrderBy() or .Sort() method
Use Sort() like
//If you want to sort collection by Id then
myMembers.Sort(x => x.Id);
//If you want to sort collection by FirstName then
myMembers.Sort(x => x.FirstName);
...
To decide between OrderBy()/Sort() read below Q&A thread
C# Sort and OrderBy comparison
Why not simply use the built in function?
myMembers.OrderBy(m => m.FirstName)
If you really want to, you can write your own wrapper around this function, but the call would look more or less identical and would kind of be reinventing the wheel.
something like this extension method:
public static IEnumerable<T> OrderByWrapper<T, TKey>(this IEnumerable<T> source, Func<T,TKey> keySelector)
{
return source.OrderBy(keySelector);
}
you would call it with:
myMembers.OrderByWrapper(m => m.FirstName)

Extension method for dictionary with value implementing interface

I'm trying to implement an extension method for all dictionaries whose value is of a type that implement a certain interface.
In this case I would like to have a ToListSortedByValue() method that returns
List<KeyValuePair<string, IComparable>>
for any dictionary of type
Dictionary<string, IComparable>
that would be cool because it would allow me to use dictionaries instead of lists, but to be able to have them sorted when needed (for example when printing in files or at console).
This is what I tried, but it doesn't work, any idea why?
public static List<KeyValuePair<string, IComparable>> ToListSortedByValue(this Dictionary<string, IComparable> Dic)
{
return Dic.OrderBy(x => x.Value).ToList();
}
EDIT:
it's solved already, but for completeness sake this is the problem I got:
when trying to use the method I got the an error as if such method didn't exist. If instead of IComparable I use an actual comparable type, let's say int or a class implementing IComparable, than it would work.
Basically you need to make the method generic on the value type and then constrain that type to be IComparable<T>.
public static List<KeyValuePair<string, T>> ToListSortedByValue<T>(
this Dictionary<string, T> Dic) where T : IComparable<T>
{
return Dic.OrderBy(x => x.Value).ToList();
}
This has the added bonus of returning the values as there passed in type. You might even want to make the key type generic too so it's not limited to just string
public static List<KeyValuePair<TKey, TValue>> ToListSortedByValue<TKey, TValue>(
this Dictionary<TKey, TValue> Dic) where TValue : IComparable<TValue>
{
return Dic.OrderBy(x => x.Value).ToList();
}
You need to make your method generic, so that it extends your actual type instead of just IComparable:
public static List<KeyValuePair<string, T>> ToListSortedByValue<T>(this Dictionary<string, T> Dic) where T : IComparable<T>

Class design for read-only collection properties

I have an IDictionary<string, MyEnum?> collection that needs to be passed to a class to wrap it in a IReadOnlyDictionary<string, MyEnum> (note MyEnum but not MyEnum?).
I have come up with two designs:
Delay the wrapping to IReadOnlyDictionary<string, MyEnum> until property access:
public class MyClass
{
private readonly IEnumerable<KeyValuePair<string, MyEnum?>> _kvps;
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
_kvps = kvps;
}
public IReadOnlyDictionary<string, MyEnum> Kvps
{
get
{
var filtered = from kvp in _kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
}
Eagerly evaluate the collection in constructor
public class MyClass
{
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
Kvps = ToReadOnly(kvps);
}
public IReadOnlyDictionary<string, MyEnum> Kvps { get; }
private static IReadOnlyDictionary<string, MyEnum> ToReadOnly(
IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
var filtered = from kvp in kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
The constructor design section of the Framework Design Guidelines suggests that minimal work should be done in constructors so I am opting for the first approach. However, that means every call to MyClass.Kvps will trigger a copy of _kvps which is not ideal.
I would like to know which is a better approach (or are there other ways) in terms of:
Memory efficiency (ideally only one copy of the collection is stored in MyClass)
Performance (property access should be fast and should not trigger a copy of the KeyValuePairs)
Out of the two requirements - don't copy the key value pairs and don't store two copies - you'll have to break one.
What causes us to look at this and think that there must be a solution is that we see TValue and TValue? and our minds want to see them as being of the same type. But they are not the same type.
It becomes clearer if you imagine that instead of TValue and TValue? that these are two different types, like an int and a string, and we want to project a collection of one to a collection of the other while filtering. For example,
List<string> GetStringsFromNonNegativeInts(List<int> ints)
{
return ints.Where(i=>i>-1).Select(i=>i.ToString()).ToList();
}
That's exactly the same scenario as trying to filter a set of TValue? to a set of TValue, even without the dictionary. It's just harder to see. TValue and TValue? code-blind us.
There are only two ways to do this. One is to copy each time, and the other is to keep two lists in synchronization.
EDIT: If you want the latest source values, best way is to implement your own class that implements IReadOnlyDictionary. Initialize this with a private field of ReadOnlyDictionary<string, MyEnum?>. Each call will do the lookup, and if the key exists AND HasValue, return the value.
Note that this implementation depends on the reference to the original values being passed in as an IReadOnlyDictionary to avoid having to copy values over.
public class MyReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue> where TValue : struct
{
// other methods to implement here...
public MyReadOnlyDictionary(IReadOnlyDictionary<TKey, TValue?> kvps)
{
_kvps = kvps;
}
private IReadOnlyDictionary<TKey, TValue?> _kvps;
new public TValue this[TKey key]
{
get
{
TValue? val = _kvps[key];
if (val.HasValue)
return val.Value;
throw new KeyNotFoundException();
}
}
}

Getting Proper Type Inference for a more complicated type in a Generic Method

I am working in the .NET 2.0 framework. I have some code working, just want it working a little more elegantly.
I have a need to effectively "mirror" a Dictionary object such that if we start with an object like this
Dictionary<TKey,TValue> StartDictionary;
We can Mirror it like this
Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);
And we would end up with a new dictionary with the values and keys being swapped for each KeyValuePair
Before anyone asks me why: the source dictionary is fairly large and loaded once from reflection calls when my program loads. I don't want to run the same reflection calls a second time to load the mirrored dictionary. Creating a mirrored Dictionary and populating its values and keys the way I came up with seemed to me to be much less costly.
So being the kind of person that hates to rewrite things, I decided to write a Generic method in a helper class I have to do the Mirror using Generics.
Now mind you I've written simple Generic methods before for normal scalar types
Here's what I came up with
public static TOutDic MirrorDictionary<TInDic, TOutDic>(TInDic InDictionary)
where TInDic : IDictionary
where TOutDic : IDictionary
{
Type[] KVPTypes = typeof(TInDic).GetGenericArguments();
Type TKey = KVPTypes[0];
Type TValue = KVPTypes[1];
Type TDic = typeof(Dictionary<,>).MakeGenericType(TValue, TKey);
IDictionary OutDic = (IDictionary)Activator.CreateInstance(TDic);
foreach (DictionaryEntry DE in (IDictionary)InDictionary) OutDic.Add(DE.Value, DE.Key);
return (TOutDic)OutDic;
}
A little bit there but it works, Loads up the Types of the Keys and Values and creates an instance of the mirrored Dictionary
Then just looping through the base DictionaryEntries of the InDictionary it adds the items to the OutDic and returns it casting it to the Type expected
Compiles just fine
Now when i go to call it I would think just like when i call a Generic method for a scalar type I could just using our code snippits above say
Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);
But that does not compile gives me
The type arguments for method MirrorDictionary(TInDic)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
So If I call it instead like this
Dictionary<TValue, TKey> MirrorDic = MirrorDictionary<Dictionary<Tkey, TValue>, Dictionary<TValue,TKey>>(StringDic);
It compiles and works like a charm.
Now the question becomes how do I make it properly infer the Type being passed into this method when the Type being passed in and the Type being passed out are complex types like in this example?
You can make life much easier for the compiler by telling it the key and value types thus:
public static Dictionary<TValue, TKey> MirrorDictionary<TKey, TValue>
(Dictionary<TKey, TValue> source)
{
Dictionary<TValue, TKey> destination = new Dictionary<TValue, TKey>();
foreach (KeyValuePair<TKey, TValue> kvp in source)
{
destination.Add(kvp.Value, kvp.Key);
}
return destination;
}
I don't think you need reflection here at all.
Sample usage:
static void Main(string[] args)
{
Dictionary<int, string> source = new Dictionary<int, string>();
source.Add(3, "foo");
source.Add(4, "bar");
DumpDic(source);
DumpDic(MirrorDictionary(source));
Console.ReadLine();
}
where DumpDic is:
public static void DumpDic<TK, TV>(Dictionary<TK, TV> dic)
{
foreach (KeyValuePair<TK, TV> keyValuePair in dic)
{
Console.WriteLine("{0} => {1}", keyValuePair.Key, keyValuePair.Value);
}
}
Here's a 3.5 solution (you can also use it in 2.0 with VS2008 and LinqBridge)
IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
return dict.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
}
And a pure 2.0 solution
IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
Dictionary<TValue, TKey> newDict = new Dictionary<TValue, TKey>();
foreach(KeyValuePair<TKey, TValue> kvp in dict)
{
newDict.Add(kvp.Value, kvp.Key);
}
return newDict;
}
Type inference should work fine with both solutions (as they have the same signature)
You could define the Out dictionary as an out parameter. Type inference does not look the type of the variable you're assigning to, only the types of the parameters. That's the reason this doesn't compile.
You need to tell it what TValue and TKey are. Unless they are defined up in the signature of the method calling this code, they don't have any specific types. You need to give it something like:
Dictionary<string, int> MirroredDictionary = MirrorDictionary(StartDictionary);

Array that can be accessed using array['Name'] in C#

Can you do
array['Name'];
In C#
Rather than:
array[0];
I know you can do that in PHP but is there an equivelent for C#, although im thinking highley unlikely :(
it's called a Dictionary in C#. Using generics you can actually index by any type. Like so:
Dictionary<Person, string> dictionary = new Dictionary<Person, string>();
Person myPerson = new Person();
dictionary[myPerson] = "Some String";
...
string someString = dictionary[myPerson];
Console.WriteLine(someString);
This obviously prints, "Some String" to the console.
This is an example of the flexibility of the dictionary. You can do it with a string as an index too, like you asked for.
Arrays don't work like that in C#, but you can add an indexer property to any class:
class MyClass
{
public string this[string key]
{
get { return GetValue(key); }
set { SetValue(key, value); }
}
}
Then you can write the type of statements you ask against this:
MyClass c = new MyClass();
c["Name"] = "Bob";
This is how string-based indexed access to Dictionary<TKey, TValue>, NameValueCollection and similar classes are implemented. You can implement multiple indexers as well, for example, one for the index and one for the name, you just add another property as above with a different parameter type.
Several built-in framework classes already have these indexers, including:
SortedList<TKey, TValue>
Dictionary<TKey, TValue>
SortedDictionary<TKey, TValue>
NameValueCollection
Lookup<TKey, TValue> (in System.Linq)
...and more. These are all designed for slightly different purposes, so you'll want to read up on each and see which one's appropriate for your requirement.
Dictionary<string, whatyouwanttostorehere> myDic =
new Dictionary<string, whatyouwanttostorehere>();
myDic.Add("Name", instanceOfWhatIWantToStore);
myDic["Name"];

Categories