public class Item
{
private int _rowID;
private Guid _itemGUID;
public Item() { }
public int Rid
{
get
{
return _rowID;
}
set { }
}
public Guid IetmGuid
{
get
{
return _itemGuid;
}
set
{
_itemGuid= value;
}
}
}
The above is my custom object.
I have a list:
List<V> myList = someMethod;
where V is of type Item, my object.
I want to iterate and get the properties as such
foreach(V element in mylist)
{
Guid test = element.IetmGuid;
}
When I debug and look at the 'element' object I can see all the properties in the 'Quickwatch' but I cannot do element.IetmGuid.
Are you putting a constraint on the generic type V? You'll need to tell the runtime that V can be any type that is a subtype of your Item type.
public class MyGenericClass<V>
where V : Item //This is a constraint that requires type V to be an Item (or subtype)
{
public void DoSomething()
{
List<V> myList = someMethod();
foreach (V element in myList)
{
//This will now work because you've constrained the generic type V
Guid test = element.IetmGuid;
}
}
}
Note, it only makes sense to use a generic class in this manner if you need to support multiple kinds of Items (represented by subtypes of Item).
Try declaring your list like this:
List<Item> myList = someMethod;
foreach( object element in myList ) {
Item itm = element as Item;
if ( null == itm ) { continue; }
Guid test = itm.ItemGuid;
}
Your list should be declared like this:
List<V> myList = someMethod;
Where V is the type item.
and then your iteration was correct:
foreach(V element in myList)
{
Guid test = element.IetmGuid;
}
Related
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.
I have a custom list class List<T> from which I am creating later several lists of objects List<TypeA> MyList1, MyList2,..., List<TypeB> MyList3,... which are not instantiated at compile time. At runtime I use reflection to instantiate those lists and get their name and save it to a property (why, doesn't matter right now and I am here showing only the affected code):
List<FieldInfo> ListOfFields = new List<FieldInfo>();
foreach (FieldInfo field in this.GetType().GetFields())
{
ListOfFields.Add(field); // saves all my List<T> in the ListOfFields list
}
This procedure is a must due to several program constraints. By reflection using the FieldInfo field i can get that certain field of a type List<T> is, but i need to iterate over their elements to check if a given <T> obj (unknown) belongs to one or an other list...
Every field of the foreach loop will be of the same type List<T>.
I am trying to find out a method where to pass a <T> obj> and loop through every field (List<T>) untill I find the match obj == field[i], something like for example:
public Tuple<string, string> GetElementTupleFor<T>(T obj)
{
foreach(FieldInfo field in ListOfFields)
{
var elements = field.MyRequestForA_GetElements_Method(); // does such method exist?
for(int i=0; i<elements.Count; i++)
{
if (obj == elements[i])
{
return new Tuple<string, string>(field.Name, ""+i);
}
}
}
return new Tuple<string, string>("NotFound", "?");
}
Thanks in advance for any help!
Is the list ever going to have objects removed, or the order changed?
If not, why not change from a List<FieldInfo> objects to a list of your own wrapper class, that takes the FieldInfo and index values when an element is added to the list. Your add method becomes:
List<MyWrapper> ListOfFields = new List<MyWrapper>();
foreach (FieldInfo field in this.GetType().GetFields())
{
var myItem = new MyWrapper(field, ListOfFields.Count);
ListOfFields.Add(myItem);
}
class MyWrapper
{
public FieldInfo Field { get; private set; }
public int Index { get; private set; }
public MyWrapper(FieldInfo field, int index)
{
Field = field;
Index = index;
}
}
If the field is not static, you will have to provide the object from which the field shall be read. Your GetElementTupleFor method thus need one more parameter:
public Tuple<string, string> GetElementTupleFor<T>(object objToQuery, T obj)
{
foreach(FieldInfo field in ListOfFields)
{
var elements = field.GetValue(objToQuery) as List<T>;
if (elements != null)
{
for(int i=0; i<elements.Count; i++)
{
if (obj == elements[i])
{
return new Tuple<string, string>(field.Name, ""+i);
}
}
}
}
return new Tuple<string, string>("NotFound", "?");
}
Let say I have class:
public class TestClass
{
public string Prop1 { get; set; }
public int Field1 = 1234567890;
public string Method1() { return "ABCDEFGHIJKLMNOPQRSTUVXYZ"; }
}
... class instance and list:
TestClass TC = new TestClass();
List<object> TCValues = new List<object>();
... and populate the list with values in loop:
foreach (var v in TC.GetType().GetProperties()) // or .GetFields()
{
TCValues.Add(v.GetValue(TC, null));
}
... problem is that in my particular case I need to get list of all class members first, then filter them to properties and fields (ignoring methods of course) and then read their values as I did in first example:
foreach (var v in TC.GetType().GetMembers())
{
if (v.MemberType == System.Reflection.MemberTypes.Property || v.MemberType == System.Reflection.MemberTypes.Field)
{
TCValues.Add(v.?????????); // Can't get values !
}
}
... I understand that GetMembers() returns class MemberInfo which unlike PropertyInfo and FieldInfo doesn't contain method GetValue(). Is there any way to read values from filtered property and field members inside the loop iterating through MemberInfo collection ?
In your foreach-Loop try
foreach (var v in TC.GetType().GetMembers())
{
if (v is PropertyInfo)
{
var value = ((PropertyInfo)v).GetValue(TC, null);
TCValues.Add(value);
}
else if (v is FieldInfo)
{
var value = ((FieldInfo) v).GetValue(TC);
TCValues.Add(value);
}
}
TC.GetType().GetProperty(propName).GetValue(TC);
You have to cast the members to the correct type:
foreach (var v in TC.GetType().GetMembers())
{
if (v.MemberType == System.Reflection.MemberTypes.Property)
{
TCValues.Add(((System.Reflection.PropertyInfo)v).GetValue(TC,null));
}
else if (v.MemberType == System.Reflection.MemberTypes.Field)
{
TCValues.Add(((System.Reflection.FieldInfo)v).GetValue(TC));
}
}
I wanted to know: How to add new members to the list, so that when I change the values of variables will also change the list.
For example:
int a=4;
list<int> l=new list<int>();
l.Add(a);
a=5;
foreach(var v in l)
Console.WriteLine("a="+v);
Output:
a=4
thanks
You need to use reference types if you want that to happen.
With value types, such as int, you get a copy of the variable in the list, not a copy of the reference.
See Value Types and Reference Types on MSDN.
This will not work for a list of value type variables, each time you are changing a value type variable you get a new variable value copy in a stack. So a solution would be using some kind of reference type wrapper.
class NumericWrapper
{
public int Value { get; set; }
}
var items = new List<NumericWrapper>();
var item = new NumericWrapper { Value = 10 };
items.Add(item);
// should be 11 after this line of code
item.Value++;
You could build out a wrapper container and then just update the wrapper's value as needed. Something like below, for example:
//item class
public class Item<T>
{
T Value {get;set;}
}
//usage example
private List<String> items = new List<string>();
public void AddItem( Item<string> item)
{
items.Add(item);
}
public void SetItem(Item<T> item,string value)
{
item.Value=value;
}
You will have to wrap the int inside a reference type.
Try this:
internal class Program
{
private static void Main(string[] args)
{
IntWrapper a = 4;
var list = new List<IntWrapper>();
list.Add(a);
a.Value = 5;
//a = 5; //Dont do this. This will assign a new reference to a. Hence changes will not reflect inside list.
foreach (var v in list)
Console.WriteLine("a=" + v);
}
}
public class IntWrapper
{
public int Value;
public IntWrapper()
{
}
public IntWrapper(int value)
{
Value = value;
}
// User-defined conversion from IntWrapper to int
public static implicit operator int(IntWrapper d)
{
return d.Value;
}
// User-defined conversion from int to IntWrapper
public static implicit operator IntWrapper(int d)
{
return new IntWrapper(d);
}
public override string ToString()
{
return Value.ToString();
}
}
I have this class
public class MyViewModel {
public MyClass Thing { get; set; }
public int Id { get { return Thing.Id; } }
public string Name { get { return Thing.Name; } }
}
I noticed when I bind it to an ASP.NET GridView, it automatically omits Thing, and for a good reason (ie. because otherwise it will only show the meaningless "MyNamespace.MyClass" in all rows)
I am trying to do a similar thing in this method.
public static string ConvertToCsv<T>(IEnumerable<T> items)
{
foreach (T item in items)
{
if(item is not a native/.NET class) // <-- How do you do this?
continue;
else // If it is a string/int/bool/DateTime or something meaningful
{
...
}
}
}
Not sure about performance, but you could use somthing along the lines of
if(item.GetType().Namespace.StartsWith("System"))
{
// do stuff
}
Or filter before looping
public static string ConvertToCsv<T>(IEnumerable<T> items)
{
foreach (T item in items.Where(i => i.GetType().Namespace.StartsWith("System")))
{
}
}
Edit: after a quick test the method above has some flaws, If your object is nullable (MyViewModel?) it will be picked up in this check (System.Nullable<MyViewModel>).
So perhaps you could use:
public static string ConvertToCsv<T>(IEnumerable<T> items)
{
foreach (T item in items.Where(i => i.GetType().Module.ScopeName.Equals("CommonLanguageRuntimeLibrary")))
{
}
}
Another edit:
There seems to be some issue with the last method also, But this one below is by far the fastest and most reliable, We just create a list of the System.Objects from the Assembly, and check if your item object is in that list.
private List<Type> _systemTypes;
public List<Type> SystemTypes
{
get
{
if (_systemTypes == null)
{
_systemTypes = Assembly.GetExecutingAssembly().GetType().Module.Assembly.GetExportedTypes().ToList();
}
return _systemTypes;
}
}
public static string ConvertToCsv<T>(IEnumerable<T> items)
{
foreach (T item in items.Where(i => SystemTypes.Contains(i.GetType())))
{
// is system type
}
}
You would have to look it up in a predefined hash table or dictionary ... say by enumerating all the assemblies that are part of the .NET Framework SDK and storing the fully qualified name in a dictionary.
I know this is old but I think you are looking for Method.
Type type = result.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
string prs = property.GetMethod.ToString();
if(!prs.StartsWith("System"))
{
//IS CLass
} else {
Console.WriteLine(property.Name + ":::" + property.Value);
}
}