print all variables in class C# - c#

To start I would prefer not to use reflection to accomplish this.
I have a class lets say
public class exampleClass
{
public string var1 = "one";
public string var2 = "two";
public int var3 = 3;
public string var4 = "four";
etc. etc..
}
I want to dynamically be able to iterate through that class and print out the variables. I thought about serialization but wasn't exactly sure how to implement it for this case (the only examples I could find were to XML and I don't want that) also I don't really want to change the structure of the class in any way.
The reason I'm doing that is because I'm constructing an HTML table and want to do:
for(int i = 0; i < exampleClass.Count; i++)
tbl_row = "<td>" + exampleClass[i] + "</td>";
or something similar. Any suggestions?

The easisets way would be using reflection. This should be enough :
var example = new exampleClass();
var allPublicFields = example.GetType().
GetFields(BindingFlags.Public | BindingFlags.Instance );
Use a dictionary, instead of fields: Dictionary<fieldName, fieldValue> , but this is
kind over engineering the simple a streghtforward solution: reflection over clear and maintanable structure of your strong typed class.

Complete same for building HTML with TagBuilder.
var tagBuilder = new TagBuilder("tr");
var exampleClass = new exampleClass();
tagBuilder.InnerText += "<td>Field</td><td>Value</td>";
foreach(var field in typeof(exampleClass)
.GetFields(BindingFlags.Public | BindingFlags.Instance))
{
var nameBuilder = new TagBuilder("td");
var valueBuilder = new TagBuilder("td");
nameBuilder.InnerHtml = field.Name;
valueBuilder.InnerHtml = field.GetValue(exampleClass).ToString();
tagBuilder.InnerHtml += string.Format("{0}{1}",
nameBuilder.ToString(),
valueBuilder.ToString());
}
outputs:
<tr>
<td>Field</td><td>Value</td>
<td>var1</td><td>one</td>
<td>var2</td><td>two</td>
<td>var3</td><td>3</td>
<td>var4</td><td>four</td>
<tr>

If you don't want to use reflection, how about storing the data in a dictionary, rather than in a custom class? That way you can simply iterate over the keys or values as required.

Personally, I think you're better off with reflection. You could achieve what you're trying to do if you're using .NET 4 or later and derive exampleClass from DynamicObject.
The example on this page is pretty similar to what you're looking to do.

Related

How to generate initialization of class fields with Roslyn

I know how to create a local variable inside a method, for example this:
LocalDeclarationStatement(VariableDeclaration(IdentifierName("MyClass"))
.WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("nameOfvariable"))
.WithInitializer(
EqualsValueClause(
ObjectCreationExpression(IdentifierName("MyClass")).WithArgumentList(arguments)
.WithNewKeyword(Token(SyntaxKind.NewKeyword)))))));
would give me:
MyClass nameOfvariable = new MyClass();
But say that I already created a field and now I simply want to initialize it (in a method, constructor or anything) like this:
nameOfVariable = new MyClass();
How do I do this? My guess it have to do with the VariableDeclerator but I can't find a way to get it right so I can add it to a list that contains StatementSyntaxes. I can change the VariableDecleration to "VariableDeclaration(IdentifierName(""))" too but that gives me an ugly extra space infront of the statement.
It seems like I struggle with some really basic stuff of Roslyn and I try to check http://roslynquoter.azurewebsites.net/ but that feels like the forced way to do it (feels like it create a lot more code than necessary).
Update: Should clarify that I know how to create method/constructors. I'm only looking for a way to initialize a field when I only have access to the field name and field type. So the only code I want to generate is this:
myField = new MyField();
Well you're almost there, you just need to create all that. This should do what you're interested in:
const string source = #"
using System;
class MyClass
{
void Method()
{
MyClass nameOfVariable;
}
}
";
var tree = CSharpSyntaxTree.ParseText(source);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
var semanticModel = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
var local = root.DescendantNodes().OfType<LocalDeclarationStatementSyntax>().First();
var declaration = local.Declaration;
var declarator = declaration.Variables.First();
var identifier = SyntaxFactory.IdentifierName("MyClass");
var objectCreationExpression = SyntaxFactory.ObjectCreationExpression(identifier, SyntaxFactory.ArgumentList(), null);
var equalsValueClause = SyntaxFactory.EqualsValueClause(objectCreationExpression);
var newDeclarator = declarator.WithInitializer(equalsValueClause).WithAdditionalAnnotations(Formatter.Annotation);
var newRoot = root.ReplaceNode(declarator, newDeclarator);
var formattedRoot = Formatter.Format(newRoot, Formatter.Annotation, new AdhocWorkspace());
Console.WriteLine(formattedRoot.GetText());
Console.Read();
Some explanation: you create a new identifier MyClass which will be used in your ObjectCreationExpression. Then you wrap all that in an EqualsValueClause and you set that as an initializer to your declarator. We also add the Formatter annotation to this node so we can format it later and don't end up with whitespace issues.
All that's left then is replacing the node in your original tree, formatting it and you're done:
-------------------------------------------------------------------------------
If you instead mean that you want to put the assignment on its own separately from the declaration then you have to create a new AssignmentExpression and wrap it inside a ExpressionStatement. Typically expressions and statements are distinct concepts but this ExpressionStatement allows us to treat an expression as a statement which is important because a method's body only accepts statements.
In code, it looks like this:
internal static void Execute()
{
const string source = #"
using System;
class MyClass
{
void Method()
{
MyClass nameOfVariable, another;
}
}
";
var tree = CSharpSyntaxTree.ParseText(source);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
var semanticModel = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
var local = root.DescendantNodes().OfType<LocalDeclarationStatementSyntax>().First();
var method = local.Ancestors().OfType<MethodDeclarationSyntax>().First();
var variableIdentifier = SyntaxFactory.IdentifierName("nameOfVariable");
var classIdentifier = SyntaxFactory.IdentifierName("MyClass");
var objectCreationExpression = SyntaxFactory.ObjectCreationExpression(classIdentifier, SyntaxFactory.ArgumentList(), null);
var assignment = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, variableIdentifier, objectCreationExpression);
var expressionStatement = SyntaxFactory.ExpressionStatement(assignment).WithAdditionalAnnotations(Formatter.Annotation);
var newMethod = method.AddBodyStatements(expressionStatement);
var newRoot = root.ReplaceNode(method.Body, newMethod.Body);
var formattedRoot = Formatter.Format(newRoot, Formatter.Annotation, new AdhocWorkspace());
Console.WriteLine(formattedRoot.GetText());
Console.Read();
}
Result:
After some more trying and looking I found the answer. There is something called "AssignmentExpression" that you can use.
Here is an example how to use it:
ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName("myField"),
ObjectCreationExpression(IdentifierName("MyClass")).WithArgumentList(arguments)
.WithNewKeyword(Token(SyntaxKind.NewKeyword))));
This would give you:
myField = new Myclass();
So now it's easy to seperate creation and assignment/initialization to two different statements.
Note that I'm using "using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;" so I don't have to write SyntaxFactory all the time.
Or you can goto "http://roslynquoter.azurewebsites.net/" and paste your code in the small little textbox and click "Get Roslyn API calls to generate this code".
(I can generate the code you posted above, but it is kinda long. so i use a simple example.
For example, let's say you paste "DateTime mydate2 = new DateTime()", the tool will generate the following code :-
LocalDeclarationStatement(
VariableDeclaration(
IdentifierName("DateTime"))
.WithVariables(
SingletonSeparatedList<VariableDeclaratorSyntax>(
VariableDeclarator(
Identifier("mydate2"))
.WithInitializer(
EqualsValueClause(
ObjectCreationExpression(
IdentifierName("DateTime"))
.WithArgumentList(
ArgumentList())))))).WithSemicolonToken(
MissingToken(SyntaxKind.SemicolonToken)).NormalizeWhitespace()
Then you just have to fix up the code using SyntaxFactory, for example :-
var myDeclaratyion = SyntaxFactory.LocalDeclarationStatement(
SyntaxFactory.VariableDeclaration(
SyntaxFactory.IdentifierName("DateTime")).
WithVariables(
SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
SyntaxFactory.VariableDeclarator(
SyntaxFactory.Identifier("mydate2")).
WithInitializer(
SyntaxFactory.EqualsValueClause(
SyntaxFactory.ObjectCreationExpression(
SyntaxFactory.IdentifierName("DateTime"))
.WithArgumentList(
SyntaxFactory.ArgumentList())))))).WithSemicolonToken(SyntaxFactory.MissingToken(SyntaxKind.SemicolonToken)).NormalizeWhitespace();

Fill/update the enum values at runtime in C#

I have windows app where-in i need to fill enum values at runtime by reading a text file named "Controls.txt".
As restriction, i'm not suppose to use dictionary. Below is the default values available in the enum MyControls. I have to use enums only.
public enum MyControls
{
Button1 = 0,
Button2 = 1,
Button3 = 2,
}
If Controls.txt file is available, then content of enum should change like
public enum MyControls
{
btn1 = 0,
btn2 = 1,
btn3 = 2,
}
how do i achieve this. I also came across the link Creating / Modifying Enums at Runtime but could not get idea.
I strongly think you are trying to solve the wrong problem. The value of enum is type-safety. I do not think that filling it up dynamically is a good idea. What would really be useful is to have an enum populated by a text file (for example) even before compilation. You can do this using text templates in VS.
You can find an example in my blog post here: http://skleanthous.azurewebsites.net/post/2014/05/21/Creating-enums-from-the-database-and-using-them-in-Entity-framework-5-and-later-in-model-first
Although my example loads from a db, changing it to load from a text file should be trivial.
Apart from the fact that i agree with the other answer that says that you lose type and compile time safety, using EnumBuilderClass should be the only way (thanks to huMpty duMpty's comment).
// sample "file":
string fileContent = #"
btn1 = 0,
btn2 = 1,
btn3 = 2,
";
var enumBody = fileContent.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
.Select(line => new { bothToken = line.Trim().Trim(',').Split('=') })
.Where(x => x.bothToken.Length == 2)
.Select(x => new { Name = x.bothToken[0].Trim(), Value = int.Parse(x.bothToken[1].Trim()) });
AppDomain currentDomain = AppDomain.CurrentDomain;
AssemblyName asmName = new AssemblyName("EnumAssembly");
AssemblyBuilder asmBuilder = currentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = asmBuilder.DefineDynamicModule(asmName.Name, asmName.Name + ".dll");
string enumTypeName = string.Format("{0}.{1}", typeof(MyControls).Namespace, typeof(MyControls).Name);
EnumBuilder eb = mb.DefineEnum(enumTypeName, TypeAttributes.Public, typeof(int));
foreach(var element in enumBody)
{
FieldBuilder fb1 = eb.DefineLiteral(element.Name, element.Value);
}
Type eType = eb.CreateType();
foreach (object obj in Enum.GetValues(eType))
{
Console.WriteLine("{0}.{1} = {2}", eType, obj, ((int)obj));
}
Output:
Namespacename.MyControls.btn1 = 0
Namespacename.MyControls.btn2 = 1
Namespacename.MyControls.btn3 = 2
Well, I agree that the use case above is not something I would use. I, however, do not agree when it comes to there being no use for it. We use for example use enums to classify string values for machine learning modules. We write code at runtime to use it at runtime and grouping enums is a hell of a lot faster than grouping and analysing strings. There is nothing good when using strings in large qualities. They are problematic when doing a comparison, memory allocation, garbage collections, grouping, sorting, there are just too many bytes.
Databases that manage large volumes of data will generate a hash of a string and store that, then compare the strings hash (not unique but a number) and the string at the same statement making the TSQL language use the more definitive index on the hash field to narrow the search, then comparing the string values to make sure the right value is used. in TSQL one would do it this way:
SELECT *
FROM Production.Product
WHERE CHECKSUM(N'Bearing Ball') = cs_Pname
AND Name = N'Bearing Ball';
GO
but in .net we keep thinking that comparing strings is the way to go.
It makes little sense for me to dump my code here as it is proprietary but that there is plenty of good samples out there, an Article by Bob Dain shows line by line how this can be done and is located here
A snippet of his solution looks like this:
using System;
using System.Reflection;
using System.IO;
namespace RemoteUser
{
public class RemoteUserClass
{
public RemoteUserClass()
{
// Load the remote assembly
AssemblyName name = new AssemblyName();
name.CodeBase = "file://" + Directory.GetCurrentDirectory() +
"ThirdPartyDll.dll";
Assembly assembly = AppDomain.CurrentDomain.Load(name);
// Instantiate the class
object remoteObject =
assembly.CreateInstance("ThirdPartyDll.ThirdPartyClass");
Type remoteType =
assembly.GetType("ThirdPartyDll.ThirdPartyClass");
// Load the enum type
PropertyInfo flagsInfo =
remoteType.GetProperty("ThirdPartyBitFields");
Type enumType = assembly.GetType("ThirdPartyDll.BitFields");
// Load the enum values
FieldInfo enumItem1 = enumType.GetField("AnotherSetting");
FieldInfo enumItem2 = enumType.GetField("SomethingElse");
// Calculate the new value
int enumValue1 = (int)enumItem1.GetValue(enumType);
int enumValue2 = (int)enumItem2.GetValue(enumType);
int currentValue = (int)flagsInfo.GetValue(remoteObject, null);
int newValue = currentValue | enumValue1 | enumValue2;
// Store the new value back in Options.FieldFlags
object newEnumValue = Enum.ToObject(enumType, newValue);
flagsInfo.SetValue(remoteObject, newEnumValue, null);
// Call the method
MethodInfo method = remoteType.GetMethod("DoSomeGood");
method.Invoke(remoteObject, null);
}
}
}
One can use the System.Reflection.Emit namespace for many things, one can generate a class that makes a license key for one. One can also write code, and code writing and updating code is the future.

Possible to set values of RegEx?

I'm just wondering if its possible to set my "set of values" to put to RegEx (Or any other methods if there is)...?
Here's what I need to do...
string myString = "Hello<<Prefix>> <<surname>>!!";
My PROBLEM:
I need to replace those strings with "<<....>>" to a value in my database.
I'm thinking of getting all those "<<....>>" and put it in a List but if you have other simpler/easier way, please help me.
Thank you in advance!
It sounds more like you need to use String.Format method. Given:
public class User
{
public string Prefix {get; set;}
public string Surname {get; set;}
}
The output should be constructed like:
var message = String.Format("Hello {0} {1}!!", user.Prefix, user.Surname);
A keyword you might want to search on is templating. One way to do it would be something like this:
var dict = new Dictionary<string,string>()
// Populate the dictionary with your key values
dict.Add("PREFIX", "Mr");
dict.Add("SURNAME", "Prescott");
string myString = "Hello<<PREFIX>> <<SURNAME>>!!";
foreach(item in dict)
{
myString = myString.Replace("<<" + item.Key + ">>", item.Value);
}
Note this is a bit naive, it will loop through an entire dictionary you load even if there is only one element to replace.

Using variable in the name

Is it possible to use a variable to access 2 variables without naming another variable?
For example, to:
LOG.dig.CNLog = 7;
LOG.value.CNLog = 17;
I would like to use something like this
string a = "dig";
string b = "value";
LOG.[a].CNLog = 7;
LOG.[b].CNLog = 17;
It's possible to use this? If yes what is the correct format?
Thanks
You can use a Dictionary<string, int>. An example:
var dict = new Dictionary<string, int>();
dict.Add("test", 1);
var testVal = dict["test"];
You can do that by using a Dictionary<TKey, TValue>.
A dictionary is a collection of keys and values. In your case you probably would like to use a Dictionary<string, LogClass> then you can have something like this:
Assuming LogClass is your class...
public class LogClass
{
public int CNLog { get; set; }
}
string a = "dig";
string b = "value";
dictionary[a].CNLog = 7;
dictionary[b].CNLog = 17;
But of course before doing that you would have to say what is the value that goes into dictionary[var].
dictionary[a] = new LogClass();
That is how you would use it, hopefully you will be able to adapt this solution to your code.
And you can check out a video that explains step-by-step very slowly and clearly how to work with it on Microsoft Virtual Academy: C# Fundamentas at 22:00.

Dynamically Generate Codes in C#

I have a list of Enums like the following:
public enum Evaluation : int
{
//Section 1
S1_1_1 = 579,
S1_1_2 = 584,
S1_1_3 = 589,
S1_1_4 = 594,
S1_1_5 = 599,
S1_1_6 = 604,
//Section 2
S1_2_1 = 610,
S1_2_2 = 615,
S1_2_3 = 620,
S1_2_4 = 625,
S1_2_5 = 630,
};
I want to iterate each section and use the values dynamically
int S1Count = 6;
for (int i = 1; i <= S1Count; i++)
{
VoteCount += string.IsNullOrEmpty(this.GetEvaluationValue(FormID, Evaluation.S1_1_ + i)) ? 0 : 1;
}
How can I achieve that? Thanks.
Sorry, my mistake. I tried to get the value from the database by using enum values which are IDs and I have to calculate counts, average for each section.
You can use Enum.Parse to do what you want I think though I don't reccomend it.
To use enum.Parse you'd just need to do something like:
Enum.Parse(typeof(Evaluation), String.Format("S1_1_{0}",i));
This does point at you using some dodgy methodology though. As I said in comments above you would be better off with a data structure allowing you to have sections and their contents easily differentiated. You can do this with either custom classes or maybe just a dictionary of Lists of ints...
Dictionary<int, List<int>> SectionContents;
and use it like:
foreach(int id in SectionContents[sectionNumber])
{
VoteCount += string.IsNullOrEmpty(this.GetEvaluationValue(FormID, id)) ? 0 : 1;
}
(I don't vouch for what's in the foreach, I'm just demonstrating how a dictionary of a list of ints could work).
Creating the Dictionary is easy enough and doesn't require enums. And if this is database stuff could easily be generated through a database query to get the IDs and what sections they are in and then create the data structure.
This will do it
public class Program
{
public static void Main()
{
foreach (FieldInfo fInfo in typeof(Evaluation).GetFields(BindingFlags.Public | BindingFlags.Static))
{
Console.WriteLine("Evaluation." + fInfo.Name);
}
Console.ReadLine();
}
}

Categories