natli
natli

Reputation: 3822

Get value from Dictionary holding generic type in C#

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?

Upvotes: 0

Views: 722

Answers (2)

Patrik Westerlund
Patrik Westerlund

Reputation: 464

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

Upvotes: 2

Lee
Lee

Reputation: 144126

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

Upvotes: 3

Related Questions