I'm implementing a custom data store against an in memory state tree and I'm running into some issues with my indexing. My indexes are meant to be covering, so they should return the object not just a position. An index has a name, and a List of objects. Those objects can be different underlying types so the indexed objects are IHasUUID which indicates an item has a UUID.
public class DataIndex
{
public string Name;
public IDictionary<string, List<IHasUUID>> Index;
}
public class Indexer
{
private List<DataIndex> Indexes;
...
public List<IHasUUID> GetIndexedItems(List<IHasUUID> indexBy)
{
var indexer = GetIndexByKeys<IHasUUID>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<IHasUUID>(indexer, indexHash);
}
private List<T> GetIndexValues<T>(DataIndex indexBy, string indexHash) where T : IHasUUID
{
if (indexBy == null)
return new List<T>();
return ((IList<T>)indexBy.Index[indexHash]).ToList();
}
}
I generate the key to the dictionary using a reflection method where I look at the things being used as the index key and append the type string names
So I ask my Engine to FindRecords, no problem
public List<T> FindRecords<T>(IHasUUID indexBy) where T : IHasUUID
{
var indexedIds = Indexer.GetIndexedItems(new List<IHasUUID>() { indexBy });
return ((IList<T>)indexedIds).ToList();
}
Here I run into a wall on the FindRecords return
I have
return ((IList<T>)indexedIds).ToList();
and I tried
return indexedIds.ToList();
Neither one is able to cast up to T. Is this possible?
Thanks in advance
EDIT
I do seem to be much closer,
public class DataIndex
{
public DataIndex()
{
Index = new Dictionary<string, IEnumerable<IHasUUID>>();
}
public string Name;
public Dictionary<string, IEnumerable<IHasUUID>> Index;
}
public class Indexer
{
private List<DataIndex> Indexes;
public Indexer()
{
Indexes = new List<DataIndex>();
}
public IEnumerable<T> GetIndexedItems<T>(IEnumerable<IHasUUID> indexBy) where T : IHasUUID
{
var indexer = GetIndexByKeys<T>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<T>(indexer, indexHash);
}
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string indexHash) where T : IHasUUID
{
if (dataIndex == null)
return new List<T>();
return dataIndex.Index[indexHash].ToList() as List<T>;
}
}
However I am getting null back from GetIndexValues. I also tried returning it as an IEnumerable, also null
Here's my Add to index method
public void AddManyToIndex<T>(IEnumerable<IHasUUID> keys, IEnumerable<IHasUUID> newItems) where T : IHasUUID
{
var index = GetIndexByKeys<T>(keys) ?? CreateIndex<T>(keys);
string indexKey = GetHashKey(keys);
if (!index.Index.ContainsKey(indexKey))
{
index.Index[indexKey] = new List<IHasUUID>();
}
var list = index.Index[indexKey].ToList();
list.AddRange(newItems.ToList());
index.Index[indexKey] = list as IEnumerable<IHasUUID>;
}
System.Collections.Generic.List<T> is not covariant. That is to say that, given two types T and U where a U is a T, a List<U> is not a List<T>.
This is why the cast fails, a list of a type implementing IHasUUID, T in your example, is not a List<IHasUUID>.
There are however, covariant1 generic types, such as System.Collections.Generic.IEnumerable<T> and System.Collections.Generic.IReadOnlyList<T>. For such types, given two types T and U where a U is a T, an IEnumerable<U> is an IEnumerable<T>.
In addition to solving your specific problem, using such types will also serve to make your APIs more flexible while at the same time making your implementation simpler and easier.
Consider the following:
public interface IHasUuid
{
Guid Uuid { get; }
}
public class DataIndex
{
public string Name { get; set; }
public IDictionary<string, IEnumerable<IHasUuid>> Index { get; } = new Dictionary<string, IEnumerable<IHasUuid>>();
}
public class Indexer
{
public IEnumerable<IHasUuid> GetIndexedItems(IEnumerable<IHasUuid> indexBy)
{
var indexer = GetIndexByKeys<IHasUuid>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<IHasUuid>(indexer, indexHash);
}
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string hash) where T : IHasUuid
{
if (dataIndex == null)
return Enumerable.Empty<T>();
return dataIndex.Index[hash] as IEnumerable<T>;
}
}
You can store any type that implements IEnumerable<IHasUuid> in DataIndex.Index. All generic collections in .NET implement this interface, including List<T>, HashSet<T>, ConcurrentQueue<T> and countless more.
If you wish to retain the defensive copying in the orginal code, which may well be wise, simply add the .ToWhatever() back to the code.
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string hash) where T : IHasUuid
{
if (dataIndex == null)
return Enumerable.Empty<T>();
return (dataIndex.Index[hash] as IEnumerable<T>).ToHashSet();
}
For example, you can build up a DataIndex instance like this
class Person: IHasUuid {
public Guid Uuid { get; }
public string Name { get; }
}
var index = new DataIndex {
Index = {
["People"] = new List<Person>()
}
};
var indexer = new Indexer();
var people = indexer.GetIndexValues(index, "People");
Here's a working fiddle: https://dotnetfiddle.net/qgjXR7
1: A type is covariant over its type parameter if that type parameter is declared using the out modifier. As its name suggests, the out modifier means that type parameter to which it is ascribed may only be used in output positions in the declaring type.
interface Wrapper<out T>
{
T Value { get; } // OK
T Value { get; set; } // Error
void SetValue(T value); // Error
}
Interface and delegate types can declare covariant type parameters, concrete types such as classes and structs may not.
Related
How do I make this expression dynamic based on the generic type passed in the parameter?
In the simplified form:
public static class CompareService
{
public static List<T> Run<T>(List<T> database_list, string directory_path)
{
var csv_list = CompareService.MergeRecordsFromFiles<T>(directory);
return CompareService.RunComparison<T>(database_list, csv_list);
}
public static T CompareData<T>(List<T> database_list, List<T> csv_list)
{
var diff = new List<T>();
foreach (var db_item in database_list)
{
// ...
// if T is of type Deathstar compare reference_number property
// if T is of type Stormtrooper compare id property
// if T is of type Sith compare id and anger_level property
var csv_item = csv_list.FirstOrDefault(x => x.reference_number == db_item.reference_number);
// Comparison code
ComparisonResult result = compareLogic.Compare(db_item, csv_item);
// ...
}
return diff;
}
}
It is called from another generic service:
public static void Whatever<T>(List<T> list)
{
// ...
var directory_path = "C:\";
var delta = CompareService.CompareData<T>(list, directory_path);
// ...
}
The most naive implementation would be to check if your itemToFind can be cast to DeathStar, StormTrooper or Sith and if so call the instances property.
var deathStar = itemToFind as DeathStar;
if(deathStar != null)
return database_list.Where(x => ((DeathStar)x).reference_number == deathStar.reference_number).FirstOrDefault();
else
{
var sith = itemToFind as Sith;
if(sith != null)
return database_list.Where(x => ((Sith)x).anger_level == sith.anger_level).FirstOrDefault();
else
return database_list.Where(x => ((StormTrooper)x).id== ((StormTrooper)item).id).FirstOrDefault();
}
This is quite cumbersome, including many casts. In particular it completely bypasses the actual benefits of generics using any arbitrary type (that fullfills the constraints if existing). In your case you´d have a generic method that will only wortk for three decent types.
A better approach is to let all your classes implement a common interface that defines a property, for instance:
interface IObject {
int Level { get; }
}
Now all classes define that level-property:
clas DeathStar : IObject
{
public int Level { get { return this.reference_number; } }
}
clas Sith : IObject
{
public int Level { get { return this.anger_level; } }
}
clas StormTrooper: IObject
{
public int Level { get { return this.id; } }
}
Than you can use a constraint on your type T to implement that interface:
public static T CompareData<T>(List<T> list, T itemToFind) where T: IObject
Why not like this:
public static T CompareData<T>(List<T> list, Func<T, bool> predicate)
{
return database_list.FirstOrDefault(predicate);
}
And then use it like this:
var itemToFind = new ItemToFind();
var myObjectList = new List<MyObject>();
var item = CompareData<MyObject>(myObjectList, x=> x.MyObjectProperty == itemToFind.Id);
You could add a property selector:
public static class CompareService
{
public static T CompareData<T>(this List<T> list, T itemToFind, Func<T, int> propSelector)
{
int propToFind = propSelector(itemToFind); // cache
return database_list.FirstOrDefault(x => propSelector(x) == propToFind);
}
}
And call it like that:
listOfDeathstars.CompareData(deathStarToFind, ds => ds.reference_number);
listOfStormtroopers.CompareData(trooperToFind, t => t.id);
listOfSiths.CompareData(sithStarToFind, sith => new { sith.id, sith.anger_level});
Note: I added the this keyword in the signature to make it an extension (not sure if you intended that but forgot the keyword). And Where(predicate).FirstOrDefault() can be reduced to FirstOrDefault(predicate).
I have a class that manages collections of objects e.g. List<Car> and List<Bike> which are atribute.
I'd like to find a way to get a reference to each of those collections in a lookup so I can implement methods such as Add<Car>(myCar) or Add(myCar) (with reflection) and it will add it to the right collection.
I tried the following,
public class ListManager
{
private Dictionary<Type, Func<IEnumerable<object>>> _lookup
= new Dictionary<Type, Func<IEnumerable<object>>>();
public ListManager()
{
this._lookup.Add(typeof(Car), () => { return this.Cars.Cast<object>().ToList(); });
this._lookup.Add(typeof(Bike), () => { return this.Bikes.Cast<object>().ToList(); });
}
public List<Car> Cars { get; set; }
public List<Bike> Bikes { get; set; }
}
but .ToList() creates a new list and not a reference, so _lookup[typeof(Car)]().Add(myCar) is only added to the dictionary list.
This will work:
public class ListManager
{
private Dictionary<Type, IList> _lookup
= new Dictionary<Type, IList>();
public ListManager()
{
_lookup.Add(typeof(Car), new List<Car>());
_lookup.Add(typeof(Bike), new List<Bike>());
}
public List<Car> Cars
{
get { return (List<Car>)_lookup[typeof(Car)]; }
}
public List<Bike> Bikes
{
get { return (List<Bike>)_lookup[typeof(Bike)]; }
}
public void Add<T>(T obj)
{
if(!_lookup.ContainsKey(typeof(T))) throw new ArgumentException("obj");
var list = _lookup[typeof(T)];
list.Add(obj);
}
}
It would be nice if both Car and Bike are derived from the same class or implement the same interface. Then you can add type constraint to the Add method to get compile errors instead of ArgumentException.
Edit
There is a small problem with the simple solution above. It will only work if the type of the objects added to the list is exactly the type stored in the _lookup dictionary. If you try to add an object derived from Car or Bike it will throw.
For example if you define a class
public class Batmobile : Car { }
Then
var listManager = new ListManager();
listManager.Add(new Batmobile());
will throw ArgumentException.
To avoid it you will need a more complicated type lookup method. Instead of simple _lookup[typeof(Car)] it should be:
private IList FindList(Type type)
{
// find all lists of type, any of its base types or implemented interfaces
var candidates = _lookup.Where(kvp => kvp.Key.IsAssignableFrom(type)).ToList();
if (candidates.Count == 1) return candidates[0].Value;
// return the list of the lowest type in the hierarchy
foreach (var candidate in candidates)
{
if (candidates.Count(kvp => candidate.Key.IsAssignableFrom(kvp.Key)) == 1)
return candidate.Value;
}
return null;
}
Try the following approach:
public class ListManager
{
private readonly Dictionary<Type, IList> _lookup = new Dictionary<Type, IList>();
public ListManager()
{
_lookup.Add(typeof(Car), new List<Car>());
_lookup.Add(typeof(Bike), new List<Bike>());
}
public List<T> Get<T>()
{
return _lookup[typeof(T)] as List<T>;
}
public void Add<T>(T item)
{
Get<T>().Add(item);
}
public List<Car> Cars
{
get { return Get<Car>(); }
}
public List<Bike> Bikes
{
get { return Get<Bike>(); }
}
}
Usage:
var listManager = new ListManager();
listManager.Add(new Car());
About derived classes
If you have some class derived from the Car, for example:
public class Ferrari : Car { }
And for some reason you don't want to have a List<Ferrari> in the dictionary, but you want to add Ferrari to the List<Car>. Then you should specify the generic type argument explicitly:
listManager.Add<Car>(new Ferrari());
It's important that the compiler checks that Ferrari is a Car at compile time, so you cannot add Ferrari to List<Bike>.
But in this case it is possible that you'll forget to specify a generic type argument somewhere and therefore you'll get an exception at run time.
To avoid it, just remove the Add<T> method. Thus you'll must explicitly specify a type of the collection each time:
listManager.Get<Car>().Add(new Ferrari());
But all the type checks will be performed at compile time.
Moreover, using the last approach you are able to manipulate lists as you like, since the Get<T> method returns a reference to the fully-functional List<T> (not just pure non-generic IList):
List<Car> cars = listManager.Get<Car>();
cars.Add(new Ferrari());
var coolCars = cars.OfType<Ferrari>();
So you don't need to reinvent the wheel by reimplementing List<T> methods in the ListManager.
You can enumerate all ListManager properties and filter by its type. This is a working example:
public class Car
{
public int Wheels { get; set; }
}
public class Bike
{
public int Pedals { get; set; }
}
public class ListManager
{
//Defina all list properties here:
public List<Car> Car { get; } = new List<Car>();
public List<Bike> Bikes { get; } = new List<Bike>();
//Gets a list instance by its element type
public object GetList(Type ElemType)
{
//Get the first property that is of the generic type List<> and that it's first generic argument equals ElemType,
//then, obtain the value for that property
return GetType().GetProperties()
.Where(x =>
x.PropertyType.IsGenericType &&
x.PropertyType.GetGenericTypeDefinition() == typeof(List<>) &&
x.PropertyType.GetGenericArguments()[0] == ElemType).FirstOrDefault().GetValue(this);
}
public void Add(object Value)
{
var ElemType = Value.GetType();
var List = GetList(ElemType);
//If list had more Add method overloads you should get all of them and filter by some other criteria
var AddMethod = List.GetType().GetMethod("Add");
//Invoke the Add method for the List instance with the first parameter as Value
AddMethod.Invoke(List,new [] { Value });
}
}
And the test console program:
class Program
{
static void Main(string[] args)
{
var L = new ListManager();
L.Add(new Car { Wheels = 4 });
L.Add(new Car { Wheels = 3 });
L.Add(new Bike { Pedals = 2 });
//Prints 2:
Console.WriteLine(L.Car.Count);
//Prints 1:
Console.WriteLine(L.Bikes.Count);
Console.ReadKey();
}
}
**Note: ** The GetList method could be cached using a Dictionary for improving its performance, since it will return always the same instance for the same type
I'm trying to sort a List<T>, without using OrderBy, OrderByDescending, where T is a custom class.
Code:
class Something
{
public string Category { get; set; }
public int Fingers { get; set; }
public DateTime Creation { get; set; }
}
The list order it's based on any property of T.
class BigRoom
{
var Room = new Room(new List<Something>());
}
class Room<T> where T: class, new()
{
List<T> baseList;
public Room(List<T> listPar)
{
baseList = listPar;
var prop = /* get any property from T with reflection... */
// How to set a comparer here, if we know prop (type, value...)
baseList.Sort(...);
// go do something with reordered list
}
}
I can do it knowing T and its properties, using lambda expressions or delegates.
list.Sort((x, y) => x.CompareTo(y));
But when getting prop values, it returns an object, which it doesn't implement CompareTo(), is there any way of achieving this, if so I'll be grateful.
Your Room constructor can be implemented like this(note i add a random for example purposes you can have the property chosen how you like it):
using System.ComponentModel;
public Room(List<T> listPar)
{
Random r = new Random(Environment.TickCount);
baseList = listPar;
var props = TypeDescriptor.GetProperties(typeof(T));
PropertyDescriptor prop = props[r.Next(props.Count)];
// How to set a comparer here, if we know prop (type, value...)
baseList.Sort((x, y) => prop.GetValue(x).ToString().CompareTo(prop.GetValue(y).ToString()));
// go do something with reordered list
}
So if the propertydescriptor is pointing to the Fingers property for example it will sort by those values,using the compareTo of the string class.
This should get you started. You'll need to actually clean up the Compare method to handle if the values are null i.e. either weren't set or are not IComparable which is required to actually be able to do comparisons.
PropertyInfo myPropertyFromReflection = GetMyPropertySomehow();
myList.Sort(new MyComparer<TransactionRequest>(myPropertyFromReflection));
public class MyComparer<T> : IComparer<T>
{
PropertyInfo _sortBy;
public MyComparer(PropertyInfo sortBy)
{
_sortBy = sortBy;
}
public int Compare(T x, T y)
{
var xValue = _sortBy.GetValue(x) as IComparable;
var yValue = _sortBy.GetValue(y) as IComparable;
return xValue.CompareTo(yValue);
}
}
objectlist is a list of objects you want to sort based on Status, then by Customer Name, then by Company Name, then by Billing Address
Assume entries in the object list have the following properties:
Status,
Customer Name,
Company Name,
Billing Address
objectlist.Sort(delegate(Object a, Object b)
{
if (String.CompareOrdinal(a.Status, b.Status) == 0)
{
return String.CompareOrdinal(a.CustomerName, b.CustomerName) == 0 ? String.CompareOrdinal(a.CompanyName, b.CompanyName) : String.CompareOrdinal(a.BillingAddress, b.BillingAddress);
}
if (a.Status.Equals("Very Important!")) { return -1; }
if (b.Status.Equals("Very Important!")) { return 1; }
if (a.Status.Equals("Important")) { return -1; }
if (b.Status.Equals("Important")) { return 1; }
if (a.Status.Equals("Not Important")){ return -1; }
return 1;
});
Hope this helps. =)
The code below add some object in MemoryCache. These objects can have different type.
I'd like a method able to return the object from MemoryCache but the return type can be different.
In my sample it's 2 but can be much more. In my sample, the type return are IT1 or List<IT2>
How can I implement this method ?
I'd like method like this (the type returned can be different depending the key) :
public ??? GetObjectFromKey(string key)
{
return _cache.Get(key);
}
Thanks,
MemoryCache _cache = MemoryCache.Default;
var it1 = new T1 { Name = "My" };
var it2 = new List<IT2>().Add(new T2 { Age = 5 });
_cache.Add("ITC1", it1, new CacheItemPolicy());
_cache.Add("ITC2", it2, new CacheItemPolicy());
var typeName = _cache.Get("ITC1").GetType();
public interface IT1
{
string Name { get; set; }
}
public class T1 : IT1
{
public string Name { get; set; }
}
public class T2 : IT2
{
public int Age { get; set; }
}
public interface IT2
{
int Age { get; set; }
}
The return type of your cache has to be either object or dynamic. You have no other possibility, because the classes you put into your cache have nothing in common.
Generics?
public T GetObjectFromKey<T>(string key)
{
return (T)_cache.Get(key);
}
If you know the type when you are calling the GetObjectFromKey you can use generics:
public T GetObjectFromKey(string key)
{
object returnObj = _cache.Get(key);
if(returnObj.GetType() == typeof(T)) // may need to also check for inheritance
{
return (T) returnObj;
}
else
{
throw new Expcetion("InvalidType");
}
}
Then when you call it:
IT1 myObj = GetObjectFromKey<IT1>("mykey");
As promised, here is how you can construct the generic method from an arbitrary type at run time (though I don't see how this is going to help!):
Type t = typeof(Something); // your type at run time
Type cacheType = _cache.GetType(); // The type that has the GetObjectFromKeyMethod
MethodInfo lGenericMethod = cacheType.GetMethod("GetObjectFromKey");
MethodInfo lTypedMethod = lMethod.MakeGenericMethod(t);
dynamic lReturn = lTypedMethod.Invoke(_cache, new object[] { "mykey" } );
Though clearly you can't do anything with lReturn as you don't know the type at compile time and you could have just returned an object (or else some common interface) and called GetType on that. Still, it is fun to write fun reflection methods like that :P
public class Table<T> where T:SomeClassWithIntegerID
{
private Dictionary<int, T> map = new Dictionary<int, T>();
public bool isInMemory(int id)
{
if (map.ContainsKey(id))
return true;
return false;
}
public T setIt(T obj)
{
map[obj.id] = obj;
}
public T getIt(int id)
{
return map[id];
}
}
Example:
private static Table<User> table = new Table<User>;
class User : SomeClassWithIntegerID
{
public string name { get; set; }
public string password { get; set; }
}
class SomeClassWithIntegerID
{
public int id { get; set; }
}
I can now check if the Table holds a user with a certain ID, because I use that as the key, but there is now no way for me to check if the Table holds a User with the name Bob or whatever. I want to be able to do something like table.isInMemory(name, "bob") but how is that possible with a generic type?
I need to create a function that allows the end user to specify the field and expected value of said field, after which Table will go over all objects of that class, stored in the Dictionary, to see if one has the field that matches that value.
Is this possible at all?
public bool IsInMemory(Func<T, bool> predicate)
{
return map.Values.Any(predicate);
}
You can then call it as:
table.IsInMemory(u => u.Name == "bob");
If you want to use a property name and value to match on you could add an overload:
public bool IsInMemory(string propertyName, object value)
{
PropertyInfo property = typeof(T).GetProperty(propertyName);
if(property == null) throw new ArgumentException("Invalid property name: " + propertyName);
var predicate = new Func<T, bool>(item => object.Equals(value, property.GetValue(item, null)));
return IsInMemory(predicate);
}
I would complement Lee's answer with a Where-method to enable querying with LINQ:
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return map.Values.Where(predicate);
}
And an example:
table.Where(x => x.name.Contains("natli"))
.OrderBy(x => x.name);
To answer your actual question, you can (if you're using .NET 4.0) use the dynamic type, which resolves all methods and such at runtime, to call methods or properties that the compiler doesn't know about from its context.
dynamic dynObject = someObject;
dynObject.SomeMethod("Hi there", 27); // Call whatever method or property you "know" exist