System.Reflection Usage [duplicate] - c#

This question already has answers here:
How to get the list of properties of a class?
(11 answers)
Closed 8 years ago.
I have a class
class ABC
{
Public int one = 10;
Public String two = "123";
public override string ToString()
{
}
}
My question i want to get fields information/values in String of Class "ABC" when ever i will create an object of that class. For example:
Public Class Test
{
public static void Main()
{
ABC a = new ABC();
a.ToString();
}
}
Now here I create an object a of class "ABC", then i want to override method of ToString() to get all fields values of class ABC in a string.
As solution this worked for me :
**Here is an other solution if we use static fields and fieldsInfo:**
class ReflectionTest
{
public static int Height = 2;
public static int Width = 10;
public static int Weight = 12;
public static string Name = "Got It";
public override string ToString()
{
string result = string.Empty;
Type type = typeof(ReflectionTest);
FieldInfo[] fields = type.GetFields();
foreach (var field in fields)
{
string name = field.Name;
object temp = field.GetValue(null);
result += "Name:" + name + ":" + temp.ToString() + System.Environment.NewLine;
}
return result;
}
}

public override string ToString()
{
Dictionary<string, string> fieldValues = new Dictionary<string, string>();
var fields = this.GetType().GetFields();
foreach (var field in fields)
{
fieldValues[field.Name] = field.GetValue(this).ToString();
}
return string.Join(", ", fieldValues.Select(x => string.Format("{0}: {1}", x.Key, x.Value)));
}

You could either use a property to retrieve the string, or override ToString(), both are shown:
public class ABC
{
private Int32 _one = 10;
public Int32 One { get { return _one; } }
private String _two = "123";
public String Two { get { return _two; } }
protected override ToString()
{
return _two;
}
}

not sure if this is what you mean;
public override ToString()
{
return string.Format("one: {1}{0}two: {2}", Environment.NewLine(), one, two);
}

So, here it is:
public class ABC
{
public int one;
public string two;
public int three;
public override string ToString()
{
string names = String.Empty;
System.Reflection.FieldInfo[] infos = this.GetType().GetFields();
foreach (System.Reflection.MemberInfo inf in infos)
{
if (names == String.Empty)
{
names = inf.Name;
}
else
{
names += ';' + inf.Name;
}
}
return names;
}
}
Enjoy!

This should do it:
public override string ToString() {
string s = "";
foreach(FieldInfo f in this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)) {
s += f.Name + "=" + f.GetValue(this).ToString() + "\r\n";
}
return s;
}
BindingFlags.Public reflects only public members. If you want private member too, use also the BindingFlags.Private flag.
You may use the this.GetType().GetFields() at object initialization, to call it only once.
This works for framework 2 also.
Change it to your needs.

Instead of using Reflection, you can use any of the following two approaches:
1: Here you can serialize your class object to a JSON object which would be more readable:
public override string ToString()
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ABC));
string str;
using (MemoryStream stream = new MemoryStream())
{
serializer.WriteObject(stream, this);
stream.Position = 0;
using (StreamReader streamReader = new StreamReader(stream, Encoding.UTF8))
{
str = streamReader.ReadToEnd();
}
}
return str;
}
2: Here you can serialize your class object to XML which can be utilize some where else:
public override string ToString()
{
XmlSerializer s = new XmlSerializer(typeof(ABC));
StringBuilder sb = new StringBuilder();
var xtw = XmlTextWriter.Create(sb);
s.Serialize
(xtw, this);
return sb.ToString();
}

Finally Get solution to my problem :)
using System;
using System.Reflection;
using System.IO;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main(string[] args)
{
MyClass mC= new MyClass();
string result = mC.ToString();
}
}
class MyClass
{
string someValue = "One";
int someValue1 = -1;
bool someValue2 = false;
float someValue3 = 2.2f;
public string SomeValue
{
get{ return this.someValue;}
}
public int SomeValue1
{
get { return this.someValue1; }
}
public bool SomeValue2
{
get { return this.someValue2; }
}
public float SomeValue3
{
get { return this.someValue3; }
}
public override string ToString()
{
string result = string.Empty;
Type type = this.GetType();
PropertyInfo [] pInfo = type.GetProperties();
for (int i = 0; i <= pInfo.Length-1; i++)
{
Type internalType = this.GetType();
PropertyInfo pInfoObject = internalType.GetProperty(pInfo[i].Name);
object value = pInfoObject.GetValue(this,null);
result += pInfo[i].Name + " : " + value.ToString() + System.Environment.NewLine;
}
return result;
}
}

Here is an other solution if we use static fields and fieldsInfo:
class ReflectionTest
{
public static int Height = 2;
public static int Width = 10;
public static int Weight = 12;
public static string Name = "Got It";
public override string ToString()
{
string result = string.Empty;
Type type = typeof(ReflectionTest);
FieldInfo[] fields = type.GetFields();
foreach (var field in fields)
{
string name = field.Name;
object temp = field.GetValue(null);
result += "Name:" + name + ":" + temp.ToString() + System.Environment.NewLine;
}
return result;
}
}

Related

Preexisting Serializer to [FromQuery] format

I want to consume an ASP.NET Core Web API method that includes [FromQuery] parameters.
Since the format is somewhat unusual, I figured there would exist a library function that would take a complex type and generate the query string formatted text - however, I can't find one.
IOW, given a controller method defined like this:
[HttpGet("testing")]
public bool Testing([FromQuery]X x)
{
return (x?.Ys[1]?.Zs[1]?.Bs[3] == 3 && x?.Ys[1]?.Zs[0]?.A == 4);
}
And an X defined like this:
public class X
{
public Y[] Ys { get; set; }
}
public class Y
{
public Z[] Zs { get; set; }
}
public class Z
{
public int A { get; set; }
public int[] Bs { get; set; }
}
First of all, what's an example of what ASP.NET [FromQuery] is expecting to encounter in the query string in order to return true?
Secondly, is there a function somewhere that can serialize an object appropriately into whatever ASP.NET is expecting, or do I need to write one?
You can use the following "serializer"
public class QueryStringSerializer
{
private static bool IsPrimitive(object obj)
{
return obj.GetType().IsPrimitive || obj is string || obj is Guid;
}
private static bool IsEnumerable(object obj)
{
return obj is IEnumerable && !IsPrimitive(obj);
}
private static bool IsComplex(object obj)
{
return !(obj is IEnumerable) && !IsPrimitive(obj);
}
private static StringBuilder ToQueryStringInternal(object obj, string prop = null)
{
StringBuilder queryString = new StringBuilder();
//skip null values
if (obj == null)
return queryString;
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
if (IsEnumerable(obj))
{
int i = 0;
foreach (object item in obj as IEnumerable)
{
string query = ToQueryStringInternal(item, $"{prop}[{i}]").ToString();
queryString.Append(query);
i++;
}
}
else if (IsComplex(obj))
{
foreach (PropertyInfo property in properties)
{
string propName = property.Name;
object value = property.GetValue(obj);
string name = prop == null ? propName : $"{prop}.{propName}";
string query = ToQueryStringInternal(value, name).ToString();
queryString.Append(query);
}
}
else
{
string encoded = HttpUtility.UrlEncode(Convert.ToString(obj));
queryString.Append($"{prop}={encoded}&");
}
return queryString;
}
public static string ToQueryString(object obj, string propertyName = null)
{
StringBuilder queryString = ToQueryStringInternal(obj, propertyName);
queryString.Length--;
return queryString.ToString();
}
}
Usage
var x = new X
{
Ys = new Y[] {
new Y {
Zs = new Z[] { new Z { } }
},
new Y {
Zs = new Z[] {
new Z { },
new Z {
A = 1,
Bs = new int[] { 0, 1, 2, 3 }
}
}
}
}
};
string query = QueryStringSerializer.ToQueryString(x);
Result
Ys[0].Zs[0].A=0&Ys[1].Zs[0].A=0&Ys[1].Zs[1].A=1&Ys[1].Zs[1].Bs[0]=0&Ys[1].Zs[1].Bs[1]=1&Ys[1].Zs[1].Bs[2]=2&Ys[1].Zs[1].Bs[3]=3
Caution
The serializer may still contain various bags. Also, do not create array with "gaps" such as
var q = new X[] {
new X { },
null, //a gap
new X { }
};
The result will be technically correct but ASP.NET model binder will bind only the first element properly.

C# - Similar as string constructor but can't return result

okay guys, i'm new in C# programming, today i was trying to create constructor which will be like a String constructor but the problem is that i have to return the result after i use it, but as i know constructora can't have return type and can't be static
using System;
class StringA {
public StringA(char x, int y) {
string res = "";
string ConvertedChar = Convert.ToString(x);
for (int i = 0; i < y; i++) {
res += ConvertedChar;
}
// How to return string res?
}
}
class MainClass {
static void Main() {
Console.WriteLine(new StringA('B', 15));
}
}
What you could do is to override the
ToString()
Method of your class StringA.
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new StringA('B', 15));
Console.Read();
}
}
class StringA
{
string res = "";
public StringA(char x, int y)
{
string ConvertedChar = Convert.ToString(x);
for (int i = 0; i < y; i++)
{
res += ConvertedChar;
}
}
public override string ToString()
{
return res;
}
}
Are you looking for a static factory method?
public static string CreateRepeatedString(char x, int y) {
return new string(x, y);
}
Perhaps you can create a public accessor for your class, or would you rather need a static factory method as #Joey stated in his answer?
See below example:
using System;
namespace YourNamespace {
class StringA {
private string privateVal = "";
public string PublicVal {
get {
return this.privateVal;
}
set {
this.privateVal = value;
}
}
public StringA(char x, int y) {
string res = "";
string ConvertedChar = Convert.ToString(x);
for (int i = 0; i < y; i++) {
res += ConvertedChar;
}
// How to return string res?
this.privateVal = res; //assign res to your accessor
}
}
class MainClass {
static void Main() {
//then you can access the public property
Console.WriteLine(new StringA('B', 15).PublicVal);
}
}
}
You could use keyword out in following way:
class StringA
{
public StringA(char x, int y, out string res)
{
res = "";
string ConvertedChar = Convert.ToString(x);
for (int i = 0; i < y; i++)
{
res += ConvertedChar;
}
// or even shorter
// res = new string(x, y);
}
}
Then you can pass some string to constrctor and get it's value changed in constructor. Then you can use it:
class MainClass
{
static void Main()
{
string res;
Console.WriteLine(new StringA('B', 15, out res));
}
}
Besides the above answers, you can also add an implicit operator
class StringA
{
private readonly string instance;
public StringA(char x, int y)
{
string res = "";
string ConvertedChar = Convert.ToString(x);
for (int i = 0; i<y; i++)
{
res += ConvertedChar;
}
this.instance = res;
}
public static implicit operator string(StringA d) => d.instance;
}
This can then be used as:
string str = new StringA('x', 10);
Console.WriteLine(new StringA('y',100));

Is it possible to make JavaScriptSerializer also populates properties without a setter?

Is it possible to make JavaScriptSerializer also populate properties without a setter? For example, a property like test.ID in the code below:
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace JavaScriptConverterTest
{
class Program
{
static void Main(string[] args)
{
List<test> list = new List<test>();
for (int i = 0; i < 2; i++)
{
list.Add(new test(Guid.NewGuid(), "Item #" + i));
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
string jsonString = serializer.Serialize(list);
List<test> newList = serializer.Deserialize<List<test>>(jsonString);
Console.Read();
}
}
class test
{
private Guid id = Guid.Empty;
public Guid ID
{
get { return id; }
// Without a setter, JavaScriptSerializer doesn't populate this property.
// set { id = value; }
}
public string name = "";
public test()
{
}
public test(Guid id, string name)
{
this.id = id;
this.name = name;
}
}
}
You can use DataContractJsonSerializer which is built in .NET Framework and has its home at System.Runtime.Serialization.Json. You just need to decorate your field with DataMemberAttribute. Let's say you have this class:
class Foo
{
private string _boo;
public Foo(string boo) => _boo = boo;
public string Boo => _boo;
}
After decorating:
[DataContract]
class Foo
{
[DataMember] private string _boo;
public Foo(string boo) => _boo = boo;
public string Boo => _boo;
}
And testing:
private static void Main(string[] args)
{
var foo = new Foo("boo");
var serializer = new DataContractJsonSerializer(typeof(Foo));
string str;
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, foo);
str = Encoding.Default.GetString(stream.ToArray());
}
Console.WriteLine(str);
Foo loadedFoo;
using (var stream = new MemoryStream(Encoding.Default.GetBytes(str)))
{
loadedFoo = serializer.ReadObject(stream) as Foo;
}
Console.WriteLine(loadedFoo.Boo);
Console.ReadLine();
}
The loadedFoo that is constructed from the json string gets "boo" as value for _boo field.

Append path to string

I need help in appeding the string to path. The problem here is that the path that i have declare cannot be call, instead it just give normal string value. here is my code.
public static string inputhistory1 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\" + Process.GetCurrentProcess().ProcessName + DateTime.Now.ToString("yyyyMMdd")+".chf";
public static string inputhistory2 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\FileExtact" + DateTime.Now.AddMonths(-1).ToString("yyyyMM") + ".chf";
public static string inputhistory3 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\FileExtact" + DateTime.Now.AddMonths(-2).ToString("yyyyMM") + ".chf";
public static string inputhistory4 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\FileExtact" + DateTime.Now.AddMonths(-3).ToString("yyyyMM") + ".chf";
public static bool checkfile(string filename)
{
bool same = false;
for (i = 1; i <= 4; i++)
{
string filechf = "inputhistory" + i;
filechf = filechf;
try
{
foreach (string line in System.IO.File.ReadAllLines(filechf))
{
if (line.Contains(filename))
{
same = true;
break;
}
else
{
same = false;
}
}
}
catch (Exception)
{
// Ignore if file does not exist.
}
if (same == true)
{
break;
}
}
}
Just to show off the expressiveness of LINQ, and the power of leveraging the tools available:
List<string> inputHistories = new List<string>
{
inputhistory1, inputhistory2, inputhistory3, inputhistory4
};
public static bool checkfile(string filename)
{
return inputHistories.Any(filename =>
File.ReadLines(filename).Any(line => line.Contains(filename)));
}
That is because you assign variable filechf with string "inputhistory" + i.
Use an array or list to store input history value.
public static string inputhistory1 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\" + Process.GetCurrentProcess().ProcessName + DateTime.Now.ToString("yyyyMMdd")+".chf";
public static string inputhistory2 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\FileExtact" + DateTime.Now.AddMonths(-1).ToString("yyyyMM") + ".chf";
public static string inputhistory3 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\FileExtact" + DateTime.Now.AddMonths(-2).ToString("yyyyMM") + ".chf";
public static string inputhistory4 = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\Log\\FileExtact" + DateTime.Now.AddMonths(-3).ToString("yyyyMM") + ".chf";
List<string> inputHistories = new List<string>();
inputHistories.Add(inputhistory1);
inputHistories.Add(inputhistory2);
inputHistories.Add(inputhistory3);
inputHistories.Add(inputhistory4);
Then you could access its value by index:
public static bool checkfile(string filename)
{
bool same = false;
//try
//{
for (i = 0; i < inputHistories.Count; i++)
{
string filechf = inputHistories[i];
try
{
foreach (string line in System.IO.File.ReadAllLines(filechf))
{
if (line.Contains(filename))
{
same = true;
break;
}
else
{
same = false;
}
}
}
catch (Exception)
{
//ignore if file does not exist
}
if (same == true)
{
break;
}
}
There are kinds of solutions may meet your requirements
you can store the variables in a dictionary:
var dictionary = new Dictionary<string,string>();
dictionary.Add("inputhistory1", inputhistory1);
dictionary.Add("inputhistory2", inputhistory2);
dictionary.Add("inputhistory3", inputhistory3);
dictionary.Add("inputhistory4", inputhistory4);
//use as below
Console.WriteLine(dictionary["inputhistory1"]);
or you can use reflection, for more information MSDN:
public class TestClass
{
public static string inputhistory1 = "value1";
public static string inputhistory2 = "value2";
public static string inputhistory3 = "value3";
public static string inputhistory4 = "value4";
}
var obj = new TestClass();
var field = typeof (TestClass).GetField("inputhistory1");
//use as below
Console.WriteLine(field.GetValue(obj));
even you can use switch/case to return your variable value

Displaying all items in another class

My problem is that I have a List<> variable connected to another class, and I want to get all the items from that List<> and put it into a string.
In the result string, i'd like to see callNum, copyNum, content, author, year, title
Here is where I'm trying to put it into a string
public class CItemControl
{
//declare a list variable
private List<CItem> mItems;
private CItem mNewItem;
//a method that instantiates the list
public CItemControl()
{
mItems = new List<CItem>();
}
//attribute to get all items
public List<CItem> Items
{
get { return mItems; }
}
public CItem NewItem
{
get { return mNewItem; }
}
//method to add item to the CItem list
public void AddItem(int callNum, int copyNum, string content, string author, string year)
{
mNewItem = new CItem(callNum, copyNum, content, author, year);
mItems.Add(mNewItem);
}
//method to return all items to a string
public CItem ListAllItems()
{
string allItems;
}
Here is the class where I'm trying to get the items from. There will be variables added later.
class CItem
{
//declare attributes
private string mTitle;
private string mAuthor;
private string mContent;
private string mYear;
private int mCopyNum;
private int mCallNum;
private bool mHold = false;
private bool mBorrowed = false;
private bool mShelf = false;
//overload a constructor
public CItem(int CallNum, int CopyNum, string Content, string Author, string Year)
{
callNum = CallNum;
copyNum = CopyNum;
content = Content;
author = Author;
year = Year;
}
//create the default constructor
public CItem()
{
callNum = 0;
copyNum = 0;
content = "";
author = "";
year = "";
}
//set attributes
public int callNum
{
get { return mCallNum; }
set { mCallNum = value; }
}
public string content
{
get { return mContent; }
set { mContent = value; }
}
public string author
{
get { return mAuthor; }
set { mAuthor = value; }
}
public string year
{
get { return mYear; }
set { mYear = value; }
}
public string title
{
get { return mTitle; }
set { mTitle = value; }
}
public int copyNum
{
get { return mCopyNum; }
set { mCopyNum = value; }
}
public bool hold
{
get { return mHold; }
}
public bool borrowed
{
get { return mBorrowed; }
}
public bool shelf
{
get { return mShelf; }
}
//display information for users
public string displayInfo()
{
return "Call Number: " + callNum + ". Copy Number: " + copyNum + ". Title: " + title +
". Author: " + author + ". Year Published: " + year + ". Content: " + content;
}
//new method to display status of item
public string displayStatus()
{
if (borrowed == true)
return "Item is currently being borrowed.";
if (shelf == true && hold == false)
return "Item is available for borrowing.";
else
return "Item is on hold";
}
Any help is much appreciated!
Thanks in advance.
ListAllItems shall look something like this
public string ListAllItems()
{
var sb = new StringBuilder(); // var is of type StringBuilder
mItems.ForEach(item => sb.Append(item.displayInfo());
return sb.ToString();
}
return String.Join("; ", allItems.Select(item => item.displayInfo()));
You don't provide a lot of informations on how and what informations you want in your result string.
Can't you achieve this objective with a simple loop ?
using System.Text;
(...)
public string ListAllItems()
{
StringBuilder allItems = new StringBuilder();
foreach(CItem itm in Items){
allItems.AppendLine(itm.displayInfo());
}
return allItems.ToString();
}
Stringbuilder is optional but is faster than string concatenation.
I don't normally like to add formatter methods to property bags like this. If you want the flexibility to change have many formatting implementations, you might want to make a seperate class do the formatting.
public interface IFormatter<in T>
{
string Format(T obj);
}
public class CItemFormatter : IFormatter<CItem>
{
public string Format(CItem item)
{
//formatting logic
}
}

Categories