I've made my own tree data structure via classes.
Now I'm stuck with really basic stuffs. I need to make output tab delimited file from data in my List <MainTreeNode>.
I think that recursion is only way?!
Tree is N-tree, and output have first row as header and other rows are values.
Tree:
MSG (MainTreeNode)
MainParam (Must have prop NAME, doesn't have to have prop VALUE)
SubParam1 (Must have prop NAME, must have prop VALUE)
SubParam2 (Must have prop NAME, doesn't have to have prop VALUE)
SubSubParam2.1 (Must have prop NAME, must have prop VALUE)
etc.
Or:
Message : Name
Param1 : ValueV1 (VALUE must, because it doesn't have children)
Param2
Param2.1 : ValueV2
Param2.2 : Value
Param2.2.1 : ValueV3
Param2.2.2 : ValueV4 ...etc.
And output have to be like this (first line is header):
Param1|Param2/Param2.1|Param2/Param2.2/Param2.2.1|Param2/Param2.2/Param2.2.2
ValueV1|ValueV2|ValueV3|ValueV4
...
So I need probably List for header and for values but I don't know how to implement that in recursion way (or any another).
Some of unfinished code:
public void PrintToTabFile(List<Message> messages, List<string> parameters)
{
foreach (string s in parameters)
{
using (StreamWriter streamWriter = new StreamWriter(#"C:\temp\" + s + ".xls"))
{
streamWriter.Write("No.\tMsgName\tMsgData1\tMsgData2\tMsgData3");
var msg = messages.Where(x => x.Parameters.Where(p => p.ParameterName == s).Count() == 1);
List<string> headers = new List<string>();
List<string> values= new List<string>();
//... Stuck!!!
}
}
}
private void Recursion(Parameter parameter, List<string> headers, List<string> values)
{
if (parameter.SubParameters.Count == 0)
{
int index = headers.IndexOf(parameter.ParameterName);
values[index] = parameter.ParameterValue;
}
else
{
foreach (Parameter p in parameter.SubParameters)
{
Recursion(p, headers, values);
//and Stuck Probably here or before recursion call
}
}
}
I won't claim that I really know what you are asking, but still I'll give it shot. To me this seems like a very basic recursion to traverse a tree structure with some weird output while you are doing it.
Try it like this:
1. Make an interface for all your classes called INode. This interface should contain the typical things like List Children, INode Parent etc.
2. Make all your classes implement this interface (or let them inherit a base class that does this)
3. Now start with your base clase and traverse recursively over all Children using the Children property and generate your output.
This should do the trick I guess. (Sorry, no VS here to put up some real code)
BTW: you'll probably find a ton of posts about this on stackoverflow already.
Related
NOTE #1: This is in Unity, so I mention a scene, if you don't know what that is, don't worry about it, it doesn't apply too much to this question.
NOTE #2: I have looked at multiple other stack overflow posts on this subject, but they were very confusing to me, and I don't have enough reputation yet to comment, so I couldn't ask for clarification on how to use the code solutions given.
I have two custom attributes that I made, AutoSave and AutoLoad, and I want to get a List of all of their data, like the name of the field, the data that the field stores, no matter the type, and the stuff that the attribute call is given, for AutoSave: a string for the file path, a string for the scene name, a enum for the save type (which stores whether or not it will save during the beginning, the end, or when a method is called with the name of this field) and an enum for the settings (which stores whether it will write over what is currently there, or add to what is there (which is a work in progress)). And for AutoLoad: a string for the file path, a string for the scene name, and a enum for the load type (which is the exact same as the AutoSave attribute).
The code that I saw that I would like to use to sort and store is this:
Type type = typeof(AutoLoad);
foreach (PropertyInfo prop in type.GetProperties())
{
var props = from p in this.GetType().GetProperties()
let attr = p.GetCustomAttributes(typeof(AutoLoad), true)
where attr.Length == 1
select new { Property = p, Attribute = attr.First() as AutoLoad };
}
I am not sure if this is right, and I dont know how to implement, sort and store this data. If I am reading this properly, this is LINQ querying, which I am not familiar with. And I am brand new to Attributes, so if I am missing something, please let me know, and an explanation of how this code works would be nice as well.
I would store these in 6 Dictionary<string, List<WhateverTypeICanStoreTheseAs>>, the string being the scene name, the List being a list of every of this data that has that particular scene name attached. 3 dictionaries for saving, 3 for loading, each one having 1 dictionary for the beginning, 1 for the custom times, and 1 for the end. If there is a better way to store this data, please let me know!
If anyone is familiar with attributes, thanks for the help!
EDIT:
Here is my current implementation of the above code, it returns nothing when calling ToString, and returns 1 when checking outer count, and returns 0 when checking inner count.:
public static List<List<AutoSType>> GetAllOfAttribute()
{
Type type = typeof(AutoSave);
List<List<AutoSType>> objs = new List<List<AutoSType>>();
foreach (PropertyInfo prop in type.GetProperties())
{
var props = from p in prop.GetType().GetProperties()
let attr = p.GetCustomAttributes(typeof(AutoSave), true)
where attr.Length == 1
select new AutoSType { Property = p, Attribute = attr.First() as AutoSave };
objs.Add(props.ToList());
}
return objs;
}
Using the method:
List<List<AutoSType>> autoSObjs = AutoSave.GetAllOfAttribute();
Debug.Log(autoSObjs.Count);
if(autoSObjs.Count > 0)
{
Debug.Log(autoSObjs[0].Count);
}
foreach(List<AutoSType> a in autoSObjs)
{
foreach(AutoSType b in a)
{
string temp = b.Attribute.ToString();
Debug.Log(temp);
}
}
ToString override:
public override string ToString()
{
return $"{filePath}, {sceneName}, {saveType.ToString()}, {saveSettings.ToString()}";
}
Using the attribute:
[AutoSave("", "Main", AutoSave.SaveType.Beginning, AutoSave.SaveSettings.AddTo)]
public int endDate;
[AutoSave("", "Main", AutoSave.SaveType.Beginning, AutoSave.SaveSettings.AddTo)]
public string startDay;
It sounds like you're trying to find all instances of AutoSave and do something based upon that. But look at your code.
If we translate your GetAllOfAttribute to psuedo-code we get
Get the type definition for AutoSave
Initialize a list to save our List<List<AutoSType>>
Iterate all of the properties on AutoSave (wait, why?)
For each property on autoSave, get the properties on the PropertyInfo class, but only if that property on PropertyInfo has an [AutoSave] on it (Pretty sure we just went WAY off the rails here)
Instead you want to
Get all types in your assembly
For those types, filter those to the ones that contain a property with [AutoSave] on it, then operate on that type/property.
Also, as with just about anything using reflection this is going to be resource-intensive so ensure you only run it once, or once per scene. You can possibly add a class-level attribute that it can key off of to avoid iterating properties on classes you don't want looked at like creating an [AutoSaveEnabled] you can attach to the class.
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
if (type.GetCustomAttribute<AutoSaveEnabled>(true) != null)
{
foreach (PropertyInfo prop in type.GetProperties())
{
AutoSave attr = prop.GetCustomAttribute<AutoSave>(true);
if (attr != null)
{
// I found the attribute!!!
// At this point, type is the class I'm looking at, prop is the decorated property, and attr is the instance of `[AutoSave]`
}
}
}
}
I currently working on an dynamic upload module. The idea is to only define the file and the data contract for each new file. Currently I'm using reflection with 2 foreach, this is some heavy code to do this. As you can see in the code I have my object containing the csv file and 2 other lists. These two lists contains all the properties of the object where I would like to do data validation on.
var myCustomObjects = CsvSettings(new CsvReader(readFile, config)).GetRecords<MyCustomObject>();
var decimalProprties = GetPropertyNames<MyCustomObject>(typeof(decimal)).ToList();
var dateProprties = GetPropertyNames<MyCustomObject>(typeof(DateTime)).ToList();
foreach (var myCustomObject in myCustomObjects)
{
foreach (var dateProperty in dateProprties)
{
var value = myCustomObject.GetType().GetProperty(dateProperty).GetValue(myCustomObject, null);
Console.WriteLine(value); //code to check and report the value
}
Console.WriteLine(myCustomObject.Een + "|" + myCustomObject.Twee + "|" + myCustomObject.Drie);
}
How can I do this with an expression or even another way to have so less heavy code?
The code seems fine as-is. You could perhaps simplify it a little by using a method that returns Key/Value pairs for all public properties of a certain type, like so (error handling elided for brevity):
public static IEnumerable<KeyValuePair<string, T>> PropertiesOfType<T>(object myObject)
{
var properties =
from property in myObject.GetType().GetProperties()
where property.PropertyType == typeof(T) && property.CanRead
select new KeyValuePair<string, T>(property.Name, (T)property.GetValue(myObject));
return properties;
}
Then you can avoid the additional call to GetProperty() in your inner loop:
foreach (var myCustomObject in myCustomObjects)
{
foreach (var dateProperty in PropertiesOfType<DateTime>(myCustomObject))
{
Console.WriteLine(dateProperty.Value); // code to check and report the value.
}
}
Also note that you don't seem to need the .ToList() calls.
I have a ListView in virtual mode, and the underlying data is being stored in a List<MyRowObject>. Each column of the ListView corresponds to a public string property of MyRowObject. The columns of my ListView are configurable during runtime, such that any of them can be disabled and they can be reordered. To return a ListViewItem for the RetrieveVirtualItem event, I have a method similar to:
class MyRowObject
{
public string[] GetItems(List<PropertyInfo> properties)
{
string[] arr = new string[properties.Count];
foreach(PropertyInfo property in properties)
{
arr[i] = (string)property.GetValue(this,null);
}
return arr;
}
}
The event handler for RetrieveVirtualItem looks similar to:
private void listView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
e.Item = new ListViewItem(_virtualList[e.ItemIndex].GetItems(_currentColumns));
}
Maybe not surprisingly, benchmarking shows that this method is significantly slower than an implementation that accessed properties directly in a hardcoded order, and the slowdown is just significant enough that I would like to find a better solution.
The most promising idea I've had is to use an anonymous delegate to tell the MyRowObject class how to directly access the properties, but if it's possible I couldn't get the semantics right (given the name of a property stored in a string, is there a way I can write a closure to directly access that property?).
So, is there a nice way to avoid using reflection to populate my ListView without losing any functionality?
The open source extension of ListView is off limit because of company policy.
You could use these 2 functions
private List<Func<T, string>> BuildItemGetters<T>(IEnumerable<PropertyInfo> properties)
{
List<Func<T, string>> getters = new List<Func<T, string>>();
foreach (var prop in properties)
{
var paramExp = Expression.Parameter(typeof(T), "p");
Expression propExp = Expression.Property(paramExp, prop);
if (prop.PropertyType != typeof(string))
propExp = Expression.Call(propExp, toString);
var lambdaExp = Expression.Lambda<Func<T, string>>(propExp, paramExp);
getters.Add(lambdaExp.Compile());
}
return getters;
}
private string[] GetItems<T>(List<Func<T, string>> properties, T obj)
{
int count = properties.Count;
string[] output = new string[count];
for (int i = 0; i < count; i++)
output[i] = properties[i](obj);
return output;
}
Call the BuildItemGetters (sorry for the name, couldn't think of anything ;) once with a list of properties you want to get from the rows. Then just call the GetItems for each row. Where obj is the row and the list is the one you got from the other function.
For T just use the class name of your Row, like:
var props = BuildItemGetters<MyRowObject>(properties);
string[] items = GetItems(props, row);
ofcourse, only call the build when the columns change
BindingSource and PropertyDescriptor are more elegant techniques for performing manual data-binding, which is more-or-less what you're doing with the ListView when it's in VirtualMode. Although it generally uses reflection internally anyway, you can rely on it to work efficiently and seamlessly.
I wrote a blog article recently which explains in detail how to use these mechanisms (although it's in a different context, the principles are the same) - http://www.brad-smith.info/blog/archives/104
Take a look at Reflection.Emit. With this, you can generate code on the fly that accesses a specific property. This CodeProject article has an interesting description of the mechanism: http://www.codeproject.com/KB/cs/fast_dynamic_properties.aspx.
I haven't throughly reviewed the code of the project, but my first impression is that the basic idea looks promising. However, one of the improvements I would make is that some of the pieces of the class should be static and shared, for example InitTypes and the created dynamic assembly. For the rest, it looks like it fits what you're looking for.
I don't know enough about c# to tell you if that is possible, but I'll go and hack my way with something like this:
once, i will try to get 'delegate pointers' for every member that I need, and will do that through reflection - if it were c++, those pointers would be vtable offsets for property getter function
will create a map with string->pointer offset
will use the map to call the getter function directly through the pointer.
Yes, it seems like a magic, but i guess that someone with enough CLR/MSIL knowledge can shed the light on that if it is remotely possible.
Here is another variant caching the get methods for each property.
public class PropertyWrapper<T>
{
private Dictionary<string, MethodBase> _getters = new Dictionary<string, MethodBase>();
public PropertyWrapper()
{
foreach (var item in typeof(T).GetProperties())
{
if (!item.CanRead)
continue;
_getters.Add(item.Name, item.GetGetMethod());
}
}
public string GetValue(T instance, string name)
{
MethodBase getter;
if (_getters.TryGetValue(name, out getter))
return getter.Invoke(instance, null).ToString();
return string.Empty;
}
}
to get a property value:
var wrapper = new PropertyWrapper<MyObject>(); //keep it as a member variable in your form
var myObject = new MyObject{LastName = "Arne");
var value = wrapper.GetValue(myObject, "LastName");
I'm coding in C# and I have a dictionary with tons of data. One of the members is "children" but when I try to write out its values, I get:
System.Object[]
I know that children contains data, probably nested data, but I'm unsure if it's a list, dictionary, array, etc.
How do I write out all the data within "children"?
The default response of any instantiated .NET type to "ToString()" is to write out the fully qualified type name.
System.Object[] means that you have an array where each element is of type "Object". This "box" could contain anything since every type in .NET derives from Object. The following may tell you what the array really contains in terms of instantiated types:
foreach (object o in children)
Console.WriteLine(o != null ? o.GetType().FullName : "null");
It it an array of object references, so you will need to iterate over it and extract the objects, For example:
// could also use IEnumerable or IEnumerable<object> in
// place of object[] here
object[] arr = (object[])foo["children"];
foreach(object bar in arr) {
Console.WriteLine(bar);
}
If you know what the objects are, you can cast etc - or you can use the LINQ OfType/Cast extension methods:
foreach(string s in arr.OfType<string>()) { // just the strings
Console.WriteLine(s);
}
Or you can test each object:
foreach(object obj in arr) { // just the strings
if(obj is int) {
int i = (int) obj;
//...
}
// or with "as"
string s = obj as string;
if(s != null) {
// do something with s
}
}
Beyond that, you are going to have to add more detail...
(Note I didn't test this code in VS, working off memory here).
object[] children = (object[])foo["children"];
foreach(object child in children)
System.Diagnostics.Debug.WriteLine(child.GetType().FullName);
This should dump out the classnames of the children.
If you are doing a foreach on foo["children"] you shouldn't be getting a failure that a public iterator isn't found since by definition an array has one (unless I missed something).
I realize that this thread is over a year old, but I wanted to post a solution I found in case anyone is wrestling with trying to get data out of the System.Object[] returned using the Cook Computing XML-RPC Library.
Once you have the Children object returned, use the following code to view the key/values contained within:
foreach (XmlRpcStruct rpcstruct in Children)
{
foreach (DictionaryEntry de in rpcstruct)
{
Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
}
Console.WriteLine();
}
"I know that children contains data, probably nested data, but I'm unsure if it's a list, dictionary, array, etc"
So the childreen is IEnumerable or not a collection
try this code
void Iterate(object children)
{
if(children is IEnumerable data)
foreach(object item in data)
Iterate(item);
else Console.WriteLine(children.ToString());
}
I am attempting to create a Clipboard stack in C#. Clipboard data is stored in System.Windows.Forms.DataObject objects. I wanted to store each clipboard entry (IDataObject) directly in a Generic list. Due to the way Bitmaps (seem to be) stored I am thinking I need to perform a deep copy first before I add it to the list.
I attempted to use Binary serialization (see below) to create a deep copy but since System.Windows.Forms.DataObject is not marked as serializable the serialization step fails. Any ideas?
public IDataObject GetClipboardData()
{
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, Clipboard.GetDataObject());
memoryStream.Position = 0;
return (IDataObject) binaryFormatter.Deserialize(memoryStream);
}
I wrote the code below for another question and maybe it could come in useful for you in this scenario:
public static class GhettoSerializer
{
// you could make this a factory method if your type
// has a constructor that appeals to you (i.e. default
// parameterless constructor)
public static void Initialize<T>(T instance, IDictionary<string, object> values)
{
var props = typeof(T).GetProperties();
// my approach does nothing to handle rare properties with array indexers
var matches = props.Join(
values,
pi => pi.Name,
kvp => kvp.Key,
(property, kvp) =>
new {
Set = new Action<object,object,object[]>(property.SetValue),
kvp.Value
}
);
foreach (var match in matches)
match.Set(instance, match.Value, null);
}
public static IDictionary<string, object> Serialize<T>(T instance)
{
var props = typeof(T).GetProperties();
var ret = new Dictionary<string, object>();
foreach (var property in props)
{
if (!property.CanWrite || !property.CanRead)
continue;
ret.Add(property.Name, property.GetValue(instance, null));
}
return ret;
}
}
However I don't think this will be the final solution to your problem though it may give you a place to start.
Look up the docks for Serializable and find the stuff about serialization helpers. You can wrap the bitmap in your own serialization code the integrates with the .net framework.
Copy of my answer to: difference between DataContract attribute and Serializable attribute in .net
My answer fits much better here than there, although above question ends with:
"... or maybe a different way of creating a deepclone?"
I once did some inspection to an object structure via Reflection to find all assemblies required for deserialization and serialize them alongside for bootstrapping.
With a bit of work one could build a similar method for deep copying. Basically you need a recursive method that carrys along a Dictionary to detect circular references. Inside the method you inspect all fields about like this:
private void InspectRecursively(object input,
Dictionary<object, bool> processedObjects)
{
if ((input != null) && !processedObjects.ContainsKey(input))
{
processedObjects.Add(input, true);
List<FieldInfo> fields = type.GetFields(BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic );
foreach (FieldInfo field in fields)
{
object nextInput = field.GetValue(input);
if (nextInput is System.Collections.IEnumerable)
{
System.Collections.IEnumerator enumerator = (nextInput as
System.Collections.IEnumerable).GetEnumerator();
while (enumerator.MoveNext())
{
InspectRecursively(enumerator.Current, processedObjects);
}
}
else
{
InspectRecursively(nextInput, processedObjects);
}
}
}
}
To get it working you need to add an output object and something like System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type) to create the most shallowest copy (even without copying references) of each field's value. Finally you can set each field with something like field.SetValue(input, output)
However this implementation does not support registered event handlers, which is _un_supported by deserializing, too. Additionally each object in the hierarchy will be broken, if its class' constructor needs to initialize anything but setting all fields. The last point only work with serialization, if the class has a respective implementation, e.g. method marked [OnDeserialized], implements ISerializable,... .