Getting value (that may not exist) from within generic object - c#

I need a list which can have its items queried for a particular property, and then returns the item if that property has the correct value. I came up with the following:
public class MyList<T>
{
public T[] items;
public Get( string name )
{
foreach( T item in items )
{
if( item.name == name )
return item;
}
return null; // if not found
}
}
The above gives a compile error because type T doesn't necessarily have the property that i'm checking. That makes sense, but what do I have to do to get this behaviour. Please note that I cannot use a Dictionary for reasons outside the scope of this question, although it is true that a Dictionary is essential what i'm trying to re-create.

Put a constraint behind your function definition
public class MyList<T> where T : YourObjectThatHasNameProperty

You could use Reflection like this:
public static Object TryGetPropertyValue(Object fromThis, String propertyName, Boolean isStatic)
{
// Get Type
Type baseType = fromThis.GetType();
// Get additional binding flags
BindingFlags addFlag = BindingFlags.Instance;
if(isStatic)
addFlag = BindingFlags.Static;
// Get PropertyInfo
PropertyInfo info = baseType.GetProperty(propertyName, BindingFlags.Public | addFlag);
// Check if we found the Property and if we can read it
if(info == null || !info.CanRead)
return null;
// Return the value
return info.GetValue(fromThis, null);
}
Edit: If the function return null, you can assume that the property does not exist on the provided Object.

You could use reflection to see if T has that property:
Type type = item.GetType();
bool hasproperty = type.GetProperties().Where(p => p.Name.Equals("name")).Any();

You need to constrain T to be of a type that has such a property:
interface INamed {
string Name { get; }
}
public class MyList<T> where T : INamed
public T[] items;
public T Get( string name ) {
foreach( T item in items ) {
if( item.Name == name )
return item;
}
return null; // if not found
}
}
Then, for instance,
class Foo : INamed {
private readonly string name;
private readonly int foo;
public string Name { get { return this.name; } }
public Foo(string name, int foo) {
this.name = name;
this.foo = foo;
}
}
MyList<Foo> list = // some instance of MyList<Foo>
Foo alice = list.Get("Alice");

Use a generic constraint.
public interface IHasName
{
string name;
}
public class MyList<T> where T : IHasName
{
public T[] items;
public Get( string name )
{
foreach( T item in items )
{
if( item.name == name )
return item;
}
return null; // if not found
}
}

Related

Interface To Generic Casting issue

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.

C# possible to use variable as property [duplicate]

is there a way to get the value of a property of a object based on its name?
For example if I have:
public class Car : Vehicle
{
public string Make { get; set; }
}
and
var car = new Car { Make="Ford" };
I want to write a method where I can pass in the property name and it would return the property value. ie:
public string GetPropertyValue(string propertyName)
{
return the value of the property;
}
return car.GetType().GetProperty(propertyName).GetValue(car, null);
You'd have to use reflection
public object GetPropertyValue(object car, string propertyName)
{
return car.GetType().GetProperties()
.Single(pi => pi.Name == propertyName)
.GetValue(car, null);
}
If you want to be really fancy, you could make it an extension method:
public static object GetPropertyValue(this object car, string propertyName)
{
return car.GetType().GetProperties()
.Single(pi => pi.Name == propertyName)
.GetValue(car, null);
}
And then:
string makeValue = (string)car.GetPropertyValue("Make");
You want Reflection
Type t = typeof(Car);
PropertyInfo prop = t.GetProperty("Make");
if(null != prop)
return prop.GetValue(this, null);
Expanding on Adam Rackis's answer - we can make the extension method generic simply like this:
public static TResult GetPropertyValue<TResult>(this object t, string propertyName)
{
object val = t.GetType().GetProperties().Single(pi => pi.Name == propertyName).GetValue(t, null);
return (TResult)val;
}
You can throw some error handling around that too if you like.
In addition other guys answer, its Easy to get property value of any object by use Extension method like:
public static class Helper
{
public static object GetPropertyValue(this object T, string PropName)
{
return T.GetType().GetProperty(PropName) == null ? null : T.GetType().GetProperty(PropName).GetValue(T, null);
}
}
Usage is:
Car foo = new Car();
var balbal = foo.GetPropertyValue("Make");
Simple sample (without write reflection hard code in the client)
class Customer
{
public string CustomerName { get; set; }
public string Address { get; set; }
// approach here
public string GetPropertyValue(string propertyName)
{
try
{
return this.GetType().GetProperty(propertyName).GetValue(this, null) as string;
}
catch { return null; }
}
}
//use sample
static void Main(string[] args)
{
var customer = new Customer { CustomerName = "Harvey Triana", Address = "Something..." };
Console.WriteLine(customer.GetPropertyValue("CustomerName"));
}
To avoid reflection you could set up a Dictionary with your propery names as keys and functions in the dictionary value part that return the corresponding values from the properties that you request.
2 Very short options, 1 with a default value if it fails:
public object GetPropertyValue_WithDefault(
object _t,
string _prop,
object _default = null
)
{
PropertyInfo pi = _t.GetType().GetProperty(_prop);
return (pi == null
? _default
: pi.GetValue(_t, null)
);
}
public object GetPropertyValue(object _t, string _prop)
{
//because of "?." will return null if property not found
return _t.GetType().GetProperty(_prop)?.GetValue(_t, null);
}

Possible to convert SomeClass<T> to SomeClass<object> where T is not "known" until runtime?

Why I ran into this issue is shown with an example below with KnownValueDefinition<T> where ideally I would like to be able to output a List<KnownValueDefinition<object>> from a static class with a bunch of static readonly KnownValueDefinition<T>s
var reflectedFields =
typeof(KnownValue)
.GetFields( BindingFlags.Static | BindingFlags.Public )
.Where( p => p.FieldType.GetGenericTypeDefinition() == typeof(KnownValueDefinition<>) );
foreach( var fieldInfo in reflectedFields )
{
object value = fieldInfo.GetValue( null );
// every conversion method I've tried here fails...
}
where KnownValueDefinition<T> is basically defined as:
public class KnownValueDefinition<T>
{
// .. private members excluded for brevity
public string Key { get { return _key; } }
public T DefaultValue { get { return _defaultValue; } }
}
The short answer is NO.
Given two classes:
class BaseClass { ... }
class DerivedClass : BaseClass { ... }
and a generic class
class Widget<T> { ... }
It's instantiations
Widget<BaseClass> {...}
Widget<DerivedClass> { ... }
are pretty much treated as independent classes. You can't "upcast" like this:
Widget<DerivedClass> instance = new Widget<DerivedClass>() ;
Widget<BaseClass> upcastInstance = (Widget<DerivedClass>)instance ;
even though it seems like a perfectl sane thing to want to do.
Further, C# (and the CLR?) has no way of saying something like
Widget<?> = instance = ... ;
to indicate that all I care about is the fact that it is some instance of Widget<T>, but that I don't care about the type of T.
There's lots of questions (and answers) on this topic: just search.
You can define and implement a covariant interface:
public interface IKnownValueDefinition<out T>
{
public string Key { get; }
public T DefaultValue { get; }
}
public class KnownValueDefinition<T> : IKnownValueDefinition<T>
{
// .. private members excluded for brevity
public string Key { get { return _key; } }
public T DefaultValue { get { return _defaultValue; } }
}
Usage:
var kvdSomeClass = new KnownValueDefinition<SomeClass>();
IKnownValueDefinition<object> kvdObject = kvd; // this works
// but this will not work
var kvdInt = newKnownValueDefinition<int>();
kvdObject = kvdInt;
Covariance & Contravariance MSDN Page
Alexei's comment gave me an idea that appears to work perfectly (at least for my purposes)!:
public class KnownValueDefinition<T> :
IKnownValueDefinition
, IKnownValueDefinition<T>
{
// .. private members excluded for brevity
public string Key { get { return _key; } }
public T DefaultValue { get { return _defaultValue; } }
public KnownValueDefinition( string key, T DefaultValue )
{
//...construction logic
}
public IKnownValueDefinition<object> GetDefault()
{
return new KnownValueDefinition<object>( this._key, this._defaultValue );
}
}
public interface IKnownValueDefinition
{
IKnownValueDefinition<object> GetDefault();
}
public interface IKnownValueDefinition<out T>
{
string Key { get; }
T DefaultValue { get; }
}
and to complete this with the usage scenario:
var knownValueDefinitions = new List<IKnownValueDefinition<object>>();
var reflectedFields =
typeof(KnownValue)
.GetFields( BindingFlags.Static | BindingFlags.Public )
.Where( p => p.FieldType.GetGenericTypeDefinition() == typeof(KnownValueDefinition<>) );
foreach( var value in reflectedFields.Select( fieldInfo => fieldInfo.GetValue( null ) ) )
KnownValueDefinitions.Add( ((IKnownValueDefinition)value).GetDefault() );

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?
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

Reading attribute of a property using reflection

I need to read the attribute of a property using reflection
For example I get the following :
[XmlElement("Id")]
[CategoryAttribute("Main"), ReadOnly(true),
Description("This property is auto-generated")]
[RulesCriteria("ID")]
public override string Id
{
get { return _ID; }
set
{
_ID = value;
}
}
i want to get the " read only "value of this property using reflection
can anybody help
It's difficult to write the code for your case without knowing the Type name. Hope below example helps.
using System;
using System.Reflection;
public class Myproperty
{
private string caption = "Default caption";
public string Caption
{
get{return caption;}
set {if(caption!=value) {caption = value;}
}
}
}
class Mypropertyinfo
{
public static int Main(string[] args)
{
Console.WriteLine("\nReflection.PropertyInfo");
// Define a property.
Myproperty Myproperty = new Myproperty();
Console.Write("\nMyproperty.Caption = " + Myproperty.Caption);
// Get the type and PropertyInfo.
Type MyType = Type.GetType("Myproperty");
PropertyInfo Mypropertyinfo = MyType.GetProperty("Caption");
// Get and display the attributes property.
PropertyAttributes Myattributes = Mypropertyinfo.Attributes;
Console.Write("\nPropertyAttributes - " + Myattributes.ToString());
return 0;
}
}
MSDN
public static bool PropertyReadOnlyAttributeValue(PropertyInfo property)
{
ReadonlyAttribute attrib = Attribute.GetCustomAttribute(property, typeof(ReadOnlyAttribute));
return attrib != null && attrib.IsReadOnly;
}
public static bool PropertyReadOnlyAttributeValue(Type type, string propertyName)
{
return PropertyReadOnlyAttributeValue(type.GetProperty(propertyName));
}
public static bool PropertyReadOnlyAttributeValue(object instance, string propertyName)
{
if (instance != null)
{
Type type = instance.GetType();
return PropertyReadOnlyAttributeValue(type, propertyName);
}
return false;
}

Categories