I am using reflection to loop through classes of a DLL and display the properties of that class; but there are cases where the property is another class, and I need to loop through that property's properties and display them.
What I currently have will only display the properties, and not sub properties:
treeView1.Nodes.Clear();
Assembly assembly = Assembly.LoadFrom(#"Path\Domain.dll");
int count = 0;
foreach (Type type in assembly.GetTypes().Where(t => t.IsClass))
{
var node = treeView1.Nodes.Add(type.FullName);
var x = ((System.Reflection.TypeInfo)((assembly.GetTypes()))[count]).DeclaredProperties;
x.ToList().ForEach(item => treeView1.Nodes[count].Nodes.Add(item.Name));
count++;
}
}
Any help to display sub properties
What you can do is recursively do an iteration. Create a member that displays the properties, and call the member itself with the sub properties. This might give you an idea:
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
MyClass myObject = new MyClass();
ListProperties(myObject.GetType(), 2);
Console.ReadLine();
}
static void ListProperties(Type type, int ident)
{
var x = type.GetProperties();
Console.WriteLine(new String(' ', ident) + "Class: " + type.FullName);
int newIdent = ident += 2;
x.ToList().Where(item => item.PropertyType.IsClass).ToList().ForEach(item => ListProperties(item.PropertyType, newIdent));
}
}
class MyClass
{
public SubClass PropertySubClass1 { get; set; }
public SubClass PropertySubClass2 { get; set; }
}
class SubClass
{
public SubSubClass PropertySubSubClass { get; set; }
}
class SubSubClass
{
}
}
In this code fragment in the Main you see that a member ListProperties is called. In this member, the property type is listed, and then it calls itself (in the last line for the sub properties).
Instead of 'ident' for pretty-printing in this example, you have to add the node text in a similar way.
The output of this example is:
Related
I have a generic method that takes T, GetResult<T>()
T represents many objects which have custom attribute [JsonProperty(Required = Required.Always)] on most of their properties. Within GetResult<T>(), I need to change T's properties to [JsonProperty(Required = Required.Default)] and I need the next method which is called from within GetResult to get the modified version of T.
Is that possible? If so, what adjustments would I need to my sample program below?
namespace StackOverflow1
{
using System;
using Newtonsoft.Json;
class Program
{
static void Main(string[] args)
{
GetResult<Person>();
Console.Read();
}
private static T GetResult<T>() where T : Base
{
// Entering this method, T is passed with Name property set to [Required = Required.Always]
// I'm changing T's Name property to [Required = Required.Default]
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
var customAttributes = property.GetCustomAttributes(true);
foreach (var attribute in customAttributes)
{
if (attribute.GetType().Name == nameof(JsonPropertyAttribute))
{
Console.WriteLine($"Original: {((JsonPropertyAttribute)attribute).Required}");
// this is the change! But it looks like this does not actually change T which I need to forward into BuildSingleResult<T>
((JsonPropertyAttribute)attribute).Required = Required.Default;
Console.WriteLine($"After modification: {((JsonPropertyAttribute)attribute).Required}");
}
}
}
// I need T to be the **modified version** which would have [Required = Required.Default]
return BuildSingleResult<T>();
}
private static T BuildSingleResult<T>() where T : Base
{
// **** this is just to write out JsonPropertyAttribute ***
var props = typeof(T).GetProperties();
foreach (var p in props)
{
var customAttributes = p.GetCustomAttributes(true);
foreach (var attr in customAttributes)
{
if (attr.GetType().Name == nameof(JsonPropertyAttribute))
{
// This shows that T still has [Required = Required.Always] but I need it to have [Required = Required.Default]
Console.WriteLine($"(expecting Default): {((JsonPropertyAttribute)attr).Required}");
}
}
}
// *** end of debug ***
return new Person { Name = "X" } as T;
}
}
class Base
{
[JsonProperty(Required = Required.Always)]
public string Name { get; set; }
}
// This is just to demonstrate using a generic type!
class Person : Base { }
}
Say I have the following code
public class FooClass
{
public int A { get; set; } = 0;
public int B { get; set; } = 0;
}
public class BarClass
{
public int X { get; set; } = 0;
public int Y { get; set; } = 0;
}
public class MyClass
{
int z = 0;
public FooClass Foo { get; set; } = new FooClass();
public BarClass Bar { get; set; } = new BarClass();
public static void MyMethod()
{
// List of MyClass objects
var myList = Enumerable.Range(1, 10).Select(_ => new MyClass()).ToList();
// Some flags set elsewhere
bool getFooAValues = true;
bool getBarYValues = true;
bool getClassZValues = true;
// Some statements that collects "field referecnes" of MyClass
var classFieldReferenceList = new List<...>();
if (getFooAValues)
classFieldReferenceList.Add(...);
if (getBarYValues)
classFieldReferenceList.Add(...);
if (getClassZValues)
classFieldReferenceList.Add(...);
// For each field reference
classFieldReferenceList.ForEach(classFieldRef =>
{
// For each class
myList.ForEach(myClassInst =>
{
// "Select"/"Apply" the reference to get the field value
var fieldValue = myClassInt.getTheFieldReferenceValue(classFieldRef);
// Do something with field value...
return fieldValue;
});
// Do something with the list of field values...
});
}
}
In this code, specifically in MyMethod, I create a list of MyClass objects. This class has a few fields, some are simply primitive types, some are instances of other classes. How can I refer to or address these fields in the form of some object I can pass around?
For example, I began writing code, akin to the following
public static void MyMethod()
{
// List of MyClass objects
var myList = Enumerable.Range(1, 10).Select(_ => new MyClass()).ToList();
// Some flags set elsewhere
bool getFooAValues = true;
bool getBarYValues = true;
bool getClassZValues = true;
if (getFooAValues)
{
var Avalues = myList.Select(myClassInst => myClassInst.Foo.A);
// Do Action X to list of values
}
if (getBarYValues)
{
var Yvalues = myList.Select(myClassInst => myClassInst.Bar.Y);
// Do Action X to list of values
}
if (getClassZValues)
{
var Zvalues = myList.Select(myClassInst => myClassInst.z);
// Do Action X to list of values
}
}
Where //Do Action X was quite a few lines of code that I would perform to each set of values (Plotting values on a plot, flags represent showing plot line or not). Though, I don't really want duplicate that code for each possible field I could refer/address within MyClass. Thus, I want to refer to a field by some "object" then "apply" that object to an instance of MyClass later to get the value of the field, if that makes sense.
I feel like this might be akin to defining a delegate? Though the delegate would be specific to some class structure?.. Or maybe there is some simple solution I have confused myself out of finding.
You can use Func<MyClass,object> delegate:
var classFieldReferenceList = new List<Func<MyClass,object>>();
if (...)
classFieldReferenceList.Add(m => m.Foo.A);
if (...)
classFieldReferenceList.Add(m => m.Foo.B);
if (...)
classFieldReferenceList.Add(m => m.Bar.X);
if (...)
classFieldReferenceList.Add(m => m.Bar.Y);
This is not ideal because object is used as the most common denominator, but that would be required for a "mixed bag" of types.
In your second example you could get away with a generic method:
private void DoActionsOnSelectedFields<T>(IEnumerable<MyClass> data, Func<MyClass,T> selector) {
foreach (T val in data.Select(selector)) {
... // Perform some common action
}
}
I have a Types project where I define custom class objects that I want to work on in my main application. The objects are basically derived from strings and parsed into a structure.
I have two problems
1 - In a separate project I have a File reader class where I scan text files for the string types I have defined. For example by regular expression. Currently I added my Types project as a project reference and I just list the regular expressions at the top of my read class. When i find a type I convert the string to the appropriate type. However how can i improve this so that is it directly connected to my Types project - so when i update it with new types the Read class knows that it should support the new types?
2 - I'm trying to create a DLL that works on these specific types after they are read from the text file. How do I tell my DLL that I want to support the types in my Types project? Do I have to make an overloaded function for each type I want to work on? Do I use an interface?
Any advice is greatly appreciated.
EDIT: Added example code of what I''m trying to do
//PROJECT 1 - handles IO operation like Reading and writing
//function in read class job is to find one of several predefined string types by regular expression...once found they are converted to the data structure (by passing string to constructor of type class defined in the other project
public class Read
{
public string[] FileList { get; set; }
private static Int64 endOffset = 0;
private FileStream readStream;
private StreamReader sr;
private System.Text.RegularExpressions.Regex type1 = new System.Text.RegularExpressions.Regex(#"#123:test");
private System.Text.RegularExpressions.Regex type2 = new System.Text.RegularExpressions.Regex(#"TESTTYPE2");
public Read(string[] fl)
{
FileList = fl;
}
public object ReturnMessage(FileStream readStream, out int x)
{
//readStream = new FileStream(file, FileMode.Open, FileAccess.Read);
x = 0;
//endOffset = 0;
bool found = false;
char ch;
string line = string.Empty;
object message = null;
while (!(x < 0)) //do this while not end of line (x = -1)
{
readStream.Position = endOffset;
//line reader
while (found == false) //keep reading characters until end of line found
{
x = readStream.ReadByte();
if (x < 0)
{
found = true;
break;
}
// else if ((x == 10) || (x == 13))
if ((x == 10) || (x == 13))
{
ch = System.Convert.ToChar(x);
line = line + ch;
x = readStream.ReadByte();
if ((x == 10) || (x == 13))
{
ch = System.Convert.ToChar(x);
line = line + ch;
found = true;
}
else
{
if (x != 10 && (x != 13))
{
readStream.Position--;
}
found = true;
}
}
else
{
ch = System.Convert.ToChar(x);
line = line + ch;
}
}//while - end line reader
//examine line (is it one of the supported types?)
if (type1.IsMatch(line))
{
message = line;
endOffset = readStream.Position;
break;
}
else
{
endOffset = readStream.Position;
found = false;
line = string.Empty;
}
}//while not end of line
return message;
}
}
//PROJECT 2 - contains classes that define the types
//TYPE1
namespace MessageTypes.Type1
{
public sealed class Type1
{
public List<Part> S2 { get; set; }
public Type1(string s)
{
S2 = new List<Part>();
string[] parts = s.Split(':');
for (int i = 0; i < parts.Length; i++)
{
S2.Add(new Part(parts[i]));
}
}
}
public sealed class Part
{
public string P { get; set; }
public Part(string s)
{
P = s;
}
}
}
//TYPE 2
namespace MessageTypes.Type2
{
public sealed class FullString
{
public string FS { get; set; }
public FullString(string s)
{
FS = s;
}
}
}
//PROJECT 3
class DoSomethingToTypeObject{
//detect type and call appropriate function to process
}
//PROJECT 4 -- MAIN PROJECT with GUI
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (tabControl1.SelectedIndex == 0) //Processing Mode 1
{
//load file list from main window - Mode1 tab
IOHandler.Read read = new IOHandler.Read(new string[2] { #"C:\file1.txt", #"C:\file2.txt" });
//read files
foreach (string file in read.FileList)
{
//while not end of stream
myobject = read.ProcessFile(file);
DoSomethingtoTypeObject DS = new DoSomethingtoTypeObject(myobject);
//write transoformed object
write(myobject);
}
}
}
}
You should use an interface, then make all of your types implement the interface. After doing that, you should then change your Read class to operate on the interface NOT the individual classes.
That way you can add as many types as you want and not have to update the Read class.
I hope I understand you correctly.
The class you create in the Type project represent some objects that have different behaviors but the same data members and you would like to be able to use these easily within your projects without the hassle of having to explicitly list these objects.
I would create some base interface that all my objects in the Types project would implement.
I would then use a Factory Class that would use reflection to collect all objects that implement said interface.
public interface iFoo
{
string FoundItem { get; set; }
string Expression { get; }
string Value { get; set; }
void sharedFunctionName();
}
public static class FooFactory
{
public static List<iFoo> GetTypeList()
{
List<iFoo> types = new List<iFoo>();
types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from t in assembly.GetTypes()
where t.IsClass && t.GetInterfaces().Contains(typeof(iFoo))
select Activator.CreateInstance(t) as iFoo);
return types;
}
}
Then your Reader would receive all necessary information for the supported types without you having to manually dictate it anymore.
Since I guess the value type would be different at some point, you could use a Generic Interface like this :
public interface iFoo
{
string FoundItem { get; set; }
string Expression { get; }
void sharedFunctionName();
}
public interface iFoo<T> : iFoo
{
T Value { get; set; }
}
public static class FooFactory
{
public static List<iFoo> GetTypeList()
{
List<iFoo> types = new List<iFoo>();
types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from t in assembly.GetTypes()
where t.IsClass && t.GetInterfaces().Contains(typeof(iFoo))
select Activator.CreateInstance(t) as iFoo);
return types;
}
}
public class FooBar : iFoo<int>
{
}
In this example the base interface iFoo is kept to ease the discovery process.
Using generic interface would allow to kept your code Type safe (as opposed to using a Value of type object) but you will have to add some logic when recovering your objects to be able to access your Value properly.
Plus, if you ever need to create functions that would require to be shared within all your objects you would be able to add extension methods within the Factory Class and VoilĂ .
EDIT:
Based on the new information:
Your Types correspond to a type of data that you will find in a file based on some regular expression.
There might be different type of transformation based on the user selection and the Type.
We know that the user will have to pick a mode from a list and this will affect the transformation to apply on the Types.
So this is what I would do :
I would move the transformation logic right into the Type class, polymophism will take care of exactly which transformation will be called.
I would put the RegularExpression to use to detect the Type into the Type itself, this will allow you to use reflection and the Factory class discuss earlier more easily.
This way, everything is standard. Your reader is aware of any new type you create in the type project without manual intervention and once detected the right transformation could be applied and the original string is always accessible.
public enum UserMode {Mode1, Mode2};
public interface iType
{
string Expression {get;}
string OriginalString {get; set;}
string Transform(UserMode Mode);
iType getNewInstance(string OriginalString);
}
public class Type1 : iType
{
public string Expression {get { return "RegularExpression"; }}
public string OriginalString {get; set;}
//Add any other private members you need to accomplish your work here.
public string Transform(UserMode Mode)
{
switch(Mode)
{
case UserMode.Mode1:
//write the transformation code for this scenario
return ResultString;
break;
}
}
public iType getNewInstance(string Original)
{
return (iType)(new Type1(){ OriginalString = Original });
}
}
public static class TypeFactory
{
public static List<iType> GetTypeList()
{
List<iType> types = new List<iType>();
types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from t in assembly.GetTypes()
where t.IsClass && t.GetInterfaces().Contains(typeof(iType))
select Activator.CreateInstance(t) as iType);
return types;
}
}
Now, all you will have to do if match the expression from the iTypes in the list.
When you have a match you do :
var TransformationReady = from t in TypeFactory.GetTypeList()
where Regex.IsMatch(YourFileLine, t.Expression)
select t.getNewInstance(Regex.Match(YourFileLine, t.Expression));
Example
public class MyItems
{
public object Test1 {get ; set; }
public object Test2 {get ; set; }
public object Test3 {get ; set; }
public object Test4 {get ; set; }
public List<object> itemList
{
get
{
return new List<object>
{
Test1,Test2,Test3,Test4
}
}
}
}
public void LoadItems()
{
foreach (var item in MyItems.itemList)
{
//get name of item here (asin, Test1, Test2)
}
}
**
I have tried this with reflection.. asin typeof(MyItems).GetFields() etc.. but that doesn't work.
How can I find out which name "item" has? Test1? Test2?? etc...
var test = typeof(MyItems).GetProperties().Select(c=>c.Name);
The above will give you an Enumerable of properties name.
if you want to get the name of the properties in the list use:
var test = typeof(MyItems).GetProperties().Select(c=>c.Name).ToList();
EDIT:
From your comment, may be you are looking for :
foreach (var item in m.itemList)
{
var test2 = (item.GetType()).GetProperties().Select(c => c.Name);
}
The "name" of the object is neither "Test1", nor "MyItems[0]".
Both those are just references to the object, that is in effect, nameless.
I do not know of any technique in C# that could give you all the references to an object, given an object, so I do not think what you want is possible, the way you want it.
You can access the name of properties with this code (see MSDN)
Type myType =(typeof(MyTypeClass));
// Get the public properties.
PropertyInfo[] myPropertyInfo = myType.GetProperties(BindingFlags.Public|BindingFlags.Instance);
for(int i=0;i<myPropertyInfo.Length;i++)
{
PropertyInfo myPropInfo = (PropertyInfo)myPropertyInfo[i];
Console.WriteLine("The property name is {0}.", myPropInfo.Name);
Console.WriteLine("The property type is {0}.", myPropInfo.PropertyType);
}
But right now I don't know any code to access the name of a reference!
I have a Class X wich uses a Class Y. The X creates the Y, but X must create Y with THE SAME constructor method was used to create instance-Y passed to X.
It is not a Clone, because I want a NEW object-Y not equals to values of instance-Y passed to X.
It is not a instance because I do not want the SAME object-Y what is pased as instance-Y to X.
I would like to pass the "constructor method and parameters" of class Y to class X and, with this information, create the new Y-instance using the ctor-method-passed.
And I don't want to devel all 'Class Y' constructor logic because, in this case both of them will be very highly coupled.
I have done a little spike to explain myself a bit better.
Thanks.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
TheSon son1 = new TheSon();
son1.TheValue = "Another Value";
TheFather<TheSon> father1 = new TheFather<TheSon>(son1);
Console.WriteLine("Result is {0}:", "Empty constructor".Equals(father1.MySon.TheValue));
Console.WriteLine("\tbecause prop. must be: '{0}' and it is: '{1}'", "Empty constructor", father1.MySon.TheValue);
}
public class TheFather<T> where T: TheSon
{
public TheSon MySon { get; set; }
public TheFather(T mySon) {
// I would like to NOT use the same object but
// use the constructor that was used to build the passed object-instance.
//
// Or perhaps pass a concrete TheSon constructor to the 'TheFather'...
this.MySon = (TheSon)mySon;
}
}
public class TheSon
{
public string TheValue { get; set; }
public TheSon()
{
this.TheValue = "Empty constructor";
}
public TheSon(string value)
{
this.TheValue = value;
}
public TheSon(string value, int element)
{
this.TheValue = value + "-> " + Convert.ToString(element);
}
}
}
}
=========SOLUTION:
Adding this constructor to the TheFather class:
public TheFather(Func<T> sonFactory)
{
this.MySon = (T)sonFactory();
}
And with this example:
static void Main(string[] args)
{
// Uncomment one of this to change behaviour....
//Func<TheSon> factory = () => new TheSon();
Func<TheSon> factory = () => new TheSon("AValue");
//Func<TheSon> factory = () => new TheSon("AValue", 1);
TheFather<TheSon> father1 = new TheFather<TheSon>(factory);
Console.WriteLine("Result is {0}:", "AValue".Equals(father1.MySon.TheValue));
Console.WriteLine("\tbecause prop. must be: '{0}' and it is: '{1}'", "AValue", father1.MySon.TheValue);
}
Works like a charm.... :-)
Thanks...
You can simply use a factory to create TheSon objects:
Func<TheSon> factory = () => new TheSon(); // creates one with default ctor
This way you can get a new object each time, but created in exactly the same way (this is not limited to a constructor; you can also include any additional code you want). Use it like this:
var oneSon = factory(); // creates one son
var secondSon = factory(); // creates another with the same constructor
var father = new TheFather(factory()); // ditto
Update: You can also change TheFather's constructor to accept a factory if you want to create TheSon inside TheFather. For example:
public TheFather(Func<T> sonFactory) {
this.MySon = (TheSon)sonFactory();
}
and
var father = new TheFather(factory);