I need a method that will be able to loop through every static property in a static class, and combine these to a string with json syntax, where key name would equal to Property name, and key value would be the value of the property.
So the result would be a string with value:
{ "StaticPropertyName_string": "string_value_of_this_property", "StaticPropertyName_int": 34 }
I have a working method that successfully does the opposite - takes a json and maps data to static fields. But can't figure out how to do it in reverse
public static void MapProfileToJson(JToken source) //// source = plain json string
{
var destinationProperties = typeof(Fields)
.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (JProperty prop in source)
{
var destinationProp = destinationProperties
.SingleOrDefault(p => p.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
var value = ((JValue)prop.Value).Value;
if (typeof(Fields).GetProperty(prop.Name) != null)
destinationProp.SetValue(null, Convert.ChangeType(value, destinationProp.PropertyType));
else
Console.WriteLine("(!) property \"" + prop.Name + "\" is not found in class... skip");
}
}
Example static class:
public static class Fields
{
public static bool BoolField { get; set; }
public static string StringField { get; set; }
public static int IntField { get; set; }
public static double DoubleField { get; set; }
}
p.s.
Key value pairs saved in string, could be wrapped at the end like
ResultString = "{ " + resultString + " }";
C# .NET 4.7.2 (console app)
As others have said, a static class is not a good design here.
However, it is possible to map it back to JSON with some simple reflection:
public static JObject MapStaticClassToJson(Type staticClassToMap)
{
var result = new JObject();
var properties = staticClassToMap.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo prop in properties)
{
result.Add(new JProperty(prop.Name, prop.GetValue(null, null)));
}
return result;
}
I think it would be nice to have some simple code to assign json properties to a static class properties too. I created this code using #RichardDeeming answer
public static void MapStaticClassFromJson(string json, Type staticClassToMap)
{
var jsonObject = JObject.Parse(json);
var properties = staticClassToMap.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo prop in properties)
prop.SetValue(null, Convert.ChangeType(jsonObject[prop.Name], prop.PropertyType, CultureInfo.CurrentCulture), null);
}
test
MapStaticClassFromJson(json,typeof(Data));
Console.WriteLine(Data.StaticPropertyName_int);
Console.WriteLine(Data.StaticPropertyName_string);
result
34
string_value_of_this_property
[System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
sealed class ColumnName : Attribute
{
// See the attribute guidelines at
// http://go.microsoft.com/fwlink/?LinkId=85236
readonly string Column;
// This is a positional argument
public ColumnName(string columnName)
{
this.Column = columnName;
}
}
public class Comment
{
[ColumnName("ID1")]
public int Id;
[ColumnName("NAME1")]
public string Name;
[ColumnName("TEST1")]
public string Test;
}
In this code you can see I have create a class comment which have an attribute ColumnName. ColumnName is my custom class which I used to define the attirubte.
Now I am looking for a sollution to find the ColumnName value for all the properties.
public static List<T> ExecuteReader<T>(string str)
{
var res = typeof(T);
return new List<T>();
}
I tried run some Stack Overflow code on my issue but it doesn't work well. What thing I am missing in my code?
Given
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = true)]
public sealed class ColumnNameAttribute : Attribute
{
public readonly string Column;
public ColumnNameAttribute(string columnName)
{
this.Column = columnName;
}
}
(by convention attributes should have a name ending in Attribute, and note that I've restricted the AttributeTargets to Propertyes and Fields) you can
public static class ColumnsCache<T>
{
public static readonly IReadOnlyDictionary<MemberInfo, string> Columns = BuildColumnsDictionary();
public static Dictionary<MemberInfo, string> BuildColumnsDictionary()
{
var dict = new Dictionary<MemberInfo, string>();
var members = typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.MemberType == MemberTypes.Field || x.MemberType == MemberTypes.Property);
foreach (MemberInfo member in members)
{
var attr = member.GetCustomAttribute<ColumnNameAttribute>(true);
if (attr != null)
{
dict.Add(member, attr.Column);
}
}
return dict;
}
}
(note the trick: we are caching the list of column names (and of fields/properties having the ColumnNameAttribute) through the usage of a generic static class. The .NET runtime will create various distinct ColumnsCache<T1>, ColumnsCache<T2>, ColumnsCache<T3>, each one with a different dictionary of columns)
Then you can
var cols = ColumnsCache<Comment>.Columns;
var colNames = cols.Values;
The cols variable will reference a dictionary MemberInfo -> string (colum name), while the colNames is a IEnumerable<string> with only the column names. If you want to use reflection with a MemberInfo you have to check if the MemberInfo is a FieldInfo or a PropertyInfo, cast it and use the FieldInfo or PropertyInfo.
I have a method that iterates the fields of a class, returning their values as a CSV. I need a way to give classes access to this method in a generic fashion.
For some reason, Statics must derive from object or you get a compile error. In this case, deriving from a different base class does increase code re-useability for me. Is there another way to accomplish my goal?
I believe the only choice I have is to make my static class an instance class.
//a data container used for Mocking in inversion of control
public class FieldContainer : ReflectionHelper<FieldContainer>
{
public static string Field1 = "Some Data";
public static string Field2 = "Persons Name";
public static string Field3 = "3030 Plane Ave.";
}
public class ReflectionHelper<T>
{
public static string ToCSV()
{
StringBuilder fieldCollector = new StringBuilder();
Type type = typeof(T);
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo f in fields)
{
fieldCollector.Append(f.GetValue(null) + ",");
}
return fieldCollector.ToString();
}
}
Your code is perfectly valid (at least technically). Your class FieldContainer is not a static class and therefore it can derive from ReflectionHelper<T>.
However, you normally would not implement the method ToCSV in a base class, because it can basically work on ANY class. Because you want to work on static members, an extension method isn't the best way either. The simplest and cleanest way to do it, will be to have a static helper class that implements this method:
public static class ReflectionHelper
{
public static string ToCSV<T>()
{
StringBuilder fieldCollector = new StringBuilder();
Type type = typeof(T);
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo f in fields)
{
fieldCollector.Append(f.GetValue(null) + ",");
}
return fieldCollector.ToString();
}
}
You can use it like this:
var csv = ReflectionHelper.ToCSV<FieldContainer>();
However, I fail to see, why you would want to implement something like that at all. It doesn't seem to make too much sense.
You could form it as an extension method, as such:
public static class ReflectionHelperExtensions
{
public static string ToCSV<T>(this T instance)
{
var type = instance.GetType();
var fields = type.GetFields();
var fieldCollector = new StringBuilder();
foreach (FieldInfo f in fields)
{
fieldCollector.Append(f.GetValue(null) + ",");
}
return fieldCollector.ToString();
}
}
This way, your field container classes don't need to derive from any given type, as this applies to all derivatives of object.
Have you concidered using an extension method?
public static class ReflectionExtensions
{
public static string ToCSV(this object input)
{
StringBuilder fieldCollector = new StringBuilder();
Type type = input.GetType();
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo f in fields)
{
fieldCollector.Append(f.GetValue(null) + ",");
}
return fieldCollector.ToString();
}
}
Then you could simply call the following on any object:
FieldContainer c = new FieldContainer();
string result = c.ToCSV();
It's fine if you have the class as an instanced type.
public abstract class ReflectionHelper<T>
{
protected ReflectionHelper()
{ }
public static string ToCsv(string delimiter = ",")
{
var fieldCollector = new StringBuilder();
var type = typeof(T);
var fields = type.GetFields();
foreach (var f in fields)
{
fieldCollector.Append(f.GetValue(null) + delimiter);
}
return fieldCollector.ToString();
}
}
public class Something : ReflectionHelper<Something>
{
protected Something() : base()
{
}
public static string Field1 = "Some Data";
public static string Field2 = "Persons Name";
public static string Field3 = "3030 Plane Ave.";
}
HI All,
I need to access the class SomeClass which is declared has a private field in the Wrapper class, using Reflection so far i have been able to get private field members . How do i cast it back to its original type so that i could access it properties and other members.
internal class Program
{
private static void Main(string[] args)
{
Wrapper wrap = new Wrapper
{
SOmeProperty = new SomeClass
{
Number = 007
}
};
Type type = wrap.GetType();
FieldInfo[] infos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var item in infos)
{
}
}
}
internal class SomeClass
{
public int Number { get; set; }
}
internal class Wrapper
{
private SomeClass _tempSomeObj;
public SomeClass SOmeProperty
{
get
{
return _tempSomeObj;
}
set
{
_tempSomeObj = value;
}
}
}
I dont know if i understand the question correct. You want the type of the private field (backing field)??
Then you could check the FieldType property of the FieldInfo....
like this:
internal class Program
{
#region Methods
private static void Main(string[] args)
{
var wrap = new Wrapper { SOmeProperty = new SomeClass { Number = 007 } };
Type type = wrap.GetType();
FieldInfo[] fieldInfos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var fieldInfo in fieldInfos)
{
if (fieldInfo.FieldType == typeof(SomeClass))
{
Console.WriteLine("Yap!");
}
}
}
#endregion
}
internal class SomeClass
{
#region Properties
public int Number { get; set; }
#endregion
}
internal class Wrapper
{
#region Properties
public SomeClass SOmeProperty { get; set; }
#endregion
}
Use PropertyInfo instead:
internal class Program
{
private static void Main(string[] args)
{
Wrapper wrap = new Wrapper
{
SOmeProperty = new SomeClass
{
Number = 007
}
};
Type type = wrap.GetType();
PropertyInfo info = type.GetProperty("SOmeProperty", BindingFlags.NonPublic | BindingFlags.Instance);
SomeClass value = (SomeClass)info.GetValue(wrap, null);
// use `value` variable here
}
}
I'm still a little fuzzy about what your're trying to do, but you can always GetType() on any object and get its actual run time type and query that for properties field of some other type for example
public void ListPropertiesOfType( object targetObject, Type propertyType ) {
foreach( var foundProperty in targetObject.GetType( ).GetProperties( ).Where( p => p.PropertyType == propertyType ) ) {
Console.WriteLine( "Name: {0}, Value: {1}", foundProperty.Name, foundProperty.GetValue( targetObject, null ) );
}
}
ListPropertiesOfType(new Wrapper(), typeof(SomeClass))
ListPropertiesOfType(new Wrapper(), typeof(SomeOtherClass))
If you want to pass in instances of Someclass and SomeClass that is also fine, just use GetType() on the instances to get the type that you can then use to find properties of that type as illustrated above. this works the same way regardless if you make the method generic and pass in "T" or if its non-generic and you pass in "object"
I have an object that needs to be serialized to an EDI format. For this example we'll say it's a car. A car might not be the best example b/c options change over time, but for the real object the Enums will never change.
I have many Enums like the following with custom attributes applied.
public enum RoofStyle
{
[DisplayText("Glass Top")]
[StringValue("GTR")]
Glass,
[DisplayText("Convertible Soft Top")]
[StringValue("CST")]
ConvertibleSoft,
[DisplayText("Hard Top")]
[StringValue("HT ")]
HardTop,
[DisplayText("Targa Top")]
[StringValue("TT ")]
Targa,
}
The Attributes are accessed via Extension methods:
public static string GetStringValue(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the stringvalue attributes
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].StringValue : null;
}
public static string GetDisplayText(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the DisplayText attributes
DisplayTextAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(DisplayTextAttribute), false) as DisplayTextAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].DisplayText : value.ToString();
}
There is a custom EDI serializer that serializes based on the StringValue attributes like so:
StringBuilder sb = new StringBuilder();
sb.Append(car.RoofStyle.GetStringValue());
sb.Append(car.TireSize.GetStringValue());
sb.Append(car.Model.GetStringValue());
...
There is another method that can get Enum Value from StringValue for Deserialization:
car.RoofStyle = Enums.GetCode<RoofStyle>(EDIString.Substring(4, 3))
Defined as:
public static class Enums
{
public static T GetCode<T>(string value)
{
foreach (object o in System.Enum.GetValues(typeof(T)))
{
if (((Enum)o).GetStringValue() == value.ToUpper())
return (T)o;
}
throw new ArgumentException("No code exists for type " + typeof(T).ToString() + " corresponding to value of " + value);
}
}
And Finally, for the UI, the GetDisplayText() is used to show the user friendly text.
What do you think? Overkill? Is there a better way? or Goldie Locks (just right)?
Just want to get feedback before I intergrate it into my personal framework permanently. Thanks.
The part you're using to serialize is fine. The deserialization part is awkwardly written. The main problem is that you're using ToUpper() to compare strings, which is easily broken (think globalization). Such comparisons should be done with string.Compare instead, or the string.Equals overload that takes a StringComparison.
The other thing is that performing these lookups again and again during deserialization is going to pretty slow. If you're serializing a lot of data, this could actually be quite noticeable. In that case, you'd want to build a map from the StringValue to the enum itself - throw it into a static Dictionary<string, RoofStyle> and use it as a lookup for the round-trip. In other words:
public static class Enums
{
private static Dictionary<string, RoofStyle> roofStyles =
new Dictionary<string, RoofStyle>()
{
{ "GTR", RoofStyle.Glass },
{ "CST", RoofStyle.ConvertibleSoft },
{ "HT ", RoofStyle.HardTop },
{ "TT ", RoofStyle.TargaTop }
}
public static RoofStyle GetRoofStyle(string code)
{
RoofStyle result;
if (roofStyles.TryGetValue(code, out result))
return result;
throw new ArgumentException(...);
}
}
It's not as "generic" but it's way more efficient. If you don't like the duplication of string values then extract the codes as constants in a separate class.
If you really need it to be totally generic and work for any enum, you can always lazy-load the dictionary of values (generate it using the extension methods you've written) the first time a conversion is done. It's very simple to do that:
static Dictionary<string, T> CreateEnumLookup<T>()
{
return Enum.GetValues(typeof(T)).ToDictionary(o => ((Enum)o).GetStringValue(),
o => (T)o);
}
P.S. Minor detail but you might want to consider using Attribute.GetCustomAttribute instead of MemberInfo.GetCustomAttributes if you only expect there to be one attribute. There's no reason for all the array fiddling when you only need one item.
Personally, I think you are abusing the language and trying to use enums in a way they were never intended. I would create a static class RoofStyle, and create a simple struct RoofType, and use an instance for each of your enum values.
Why don't you create a type with static members such as mikerobi said
Example...
public class RoofStyle
{
private RoofStyle() { }
public string Display { get; private set; }
public string Value { get; private set; }
public readonly static RoofStyle Glass = new RoofStyle
{
Display = "Glass Top", Value = "GTR",
};
public readonly static RoofStyle ConvertibleSoft = new RoofStyle
{
Display = "Convertible Soft Top", Value = "CST",
};
public readonly static RoofStyle HardTop = new RoofStyle
{
Display = "Hard Top", Value = "HT ",
};
public readonly static RoofStyle Targa = new RoofStyle
{
Display = "Targa Top", Value = "TT ",
};
}
BTW...
When compiled into IL an Enum is very similar to this class structure.
... Enum backing fields ...
.field public specialname rtspecialname int32 value__
.field public static literal valuetype A.ERoofStyle Glass = int32(0x00)
.field public static literal valuetype A.ERoofStyle ConvertibleSoft = int32(0x01)
.field public static literal valuetype A.ERoofStyle HardTop = int32(0x02)
.field public static literal valuetype A.ERoofStyle Targa = int32(0x03)
... Class backing fields ...
.field public static initonly class A.RoofStyle Glass
.field public static initonly class A.RoofStyle ConvertibleSoft
.field public static initonly class A.RoofStyle HardTop
.field public static initonly class A.RoofStyle Targa
Here is a base class I use for enumeration classes:
public abstract class Enumeration<T, TId> : IEquatable<T> where T : Enumeration<T, TId>
{
public static bool operator ==(Enumeration<T, TId> x, T y)
{
return Object.ReferenceEquals(x, y) || (!Object.ReferenceEquals(x, null) && x.Equals(y));
}
public static bool operator !=(Enumeration<T, TId> first, T second)
{
return !(first == second);
}
public static T FromId(TId id)
{
return AllValues.Where(value => value.Id.Equals(id)).FirstOrDefault();
}
public static readonly ReadOnlyCollection<T> AllValues = FindValues();
private static ReadOnlyCollection<T> FindValues()
{
var values =
(from staticField in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public)
where staticField.FieldType == typeof(T)
select (T) staticField.GetValue(null))
.ToList()
.AsReadOnly();
var duplicateIds =
(from value in values
group value by value.Id into valuesById
where valuesById.Skip(1).Any()
select valuesById.Key)
.Take(1)
.ToList();
if(duplicateIds.Count > 0)
{
throw new DuplicateEnumerationIdException("Duplicate ID: " + duplicateIds.Single());
}
return values;
}
protected Enumeration(TId id, string name)
{
Contract.Requires(((object) id) != null);
Contract.Requires(!String.IsNullOrEmpty(name));
this.Id = id;
this.Name = name;
}
protected Enumeration()
{}
public override bool Equals(object obj)
{
return Equals(obj as T);
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
public override string ToString()
{
return this.Name;
}
#region IEquatable
public virtual bool Equals(T other)
{
return other != null && this.IdComparer.Equals(this.Id, other.Id);
}
#endregion
public virtual TId Id { get; private set; }
public virtual string Name { get; private set; }
protected virtual IEqualityComparer<TId> IdComparer
{
get { return EqualityComparer<TId>.Default; }
}
}
An implementation would look like:
public sealed class RoofStyle : Enumeration<RoofStyle, int>
{
public static readonly RoofStyle Glass = new RoofStyle(0, "Glass Top", "GTR");
public static readonly RoofStyle ConvertibleSoft = new RoofStyle(1, "Convertible Soft Top", "CST");
public static readonly RoofStyle HardTop = new RoofStyle(2, "Hard Top", "HT ");
public static readonly RoofStyle Targa = new RoofStyle(3, "Targa Top", "TT ");
public static RoofStyle FromStringValue(string stringValue)
{
return AllValues.FirstOrDefault(value => value.StringValue == stringValue);
}
private RoofStyle(int id, string name, string stringValue) : base(id, name)
{
StringValue = stringValue;
}
public string StringValue { get; private set; }
}
You would use it during serialization like this:
var builder = new StringBuilder();
builder.Append(car.RoofStyle.StringValue);
...
To deserialize:
car.RoofStyle = RoofStyle.FromStringValue(EDIString.Substring(4, 3));
I don't see a problem with it - actually, I do the same. By this, I achieve verbosity with the enum, and can define how the enum is to be translated when I use it to request data, eg. RequestTarget.Character will result in "char".
Can't say I've ever seen it done that way but the consumer code is relatively simple so I'd probably enjoy using it.
The only thing that sticks out for me is the potential for consumers having to deal with nulls - which might be able to be removed. If you have control over the attributes (which you do, from the sounds of it), then there should never be a case where GetDisplayText or GetStringValue return null so you can remove
return attribs.Length > 0 ? attribs[0].StringValue : null;
and replace it with
return attribs[0].StringValue;
in order to simplify the interface for consumer code.
IMHO, the design is solid, and will work.
However, reflection tends to be a litle slow, so if those methods are used in tight loops, it might slow down the whole application.
You could try caching the the return values into a Dictionary<RoofStyle, string> so they are only reflected once, and then fetched from cache.
Something like this:
private static Dictionary<Enum, string> stringValues
= new Dictionary<Enum,string>();
public static string GetStringValue(this Enum value)
{
if (!stringValues.ContainsKey(value))
{
Type type = value.GetType();
FieldInfo fieldInfo = type.GetField(value.ToString());
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
stringValues.Add(value, attribs.Length > 0 ? attribs[0].StringValue : null);
}
return stringValues[value];
}
I know this question has already been answered, but while ago I posted the following code fragment on my personal blog, which demonstrates faking Java style enums using extension methods. You might find this method works for you, especially as it overcomes the overhead of accessing Attributes via reflection.
using System;
using System.Collections.Generic;
namespace ScratchPad
{
internal class Program
{
private static void Main(string[] args)
{
var p = new Program();
p.Run();
}
private void Run()
{
double earthWeight = 175;
double mass = earthWeight / Planet.Earth.SurfaceGravity();
foreach (Planet planet in Enum.GetValues(typeof(Planet))) {
Console.WriteLine("Your weight on {0} is {1}", planet, planet.SurfaceWeight(mass));
}
}
}
public enum Planet
{
Mercury,
Venus,
Earth,
Mars,
Jupiter,
Saturn,
Uranus,
Neptune
}
public static class PlanetExtensions
{
private static readonly Dictionary<Planet, PlanetData> planetMap = new Dictionary<Planet, PlanetData>
{
{Planet.Mercury, new PlanetData(3.303e+23, 2.4397e6)},
{Planet.Venus, new PlanetData(4.869e+24, 6.0518e6)},
{Planet.Earth, new PlanetData(5.976e+24, 6.37814e6)},
{Planet.Mars, new PlanetData(6.421e+23, 3.3972e6)},
{Planet.Jupiter, new PlanetData(1.9e+27, 7.1492e7)},
{Planet.Saturn, new PlanetData(5.688e+26, 6.0268e7)},
{Planet.Uranus, new PlanetData(8.686e+25, 2.5559e7)},
{Planet.Neptune, new PlanetData(1.024e+26, 2.4746e7)}
};
private const double G = 6.67300E-11;
public static double Mass(this Planet planet)
{
return GetPlanetData(planet).Mass;
}
public static double Radius(this Planet planet)
{
return GetPlanetData(planet).Radius;
}
public static double SurfaceGravity(this Planet planet)
{
PlanetData planetData = GetPlanetData(planet);
return G * planetData.Mass / (planetData.Radius * planetData.Radius);
}
public static double SurfaceWeight(this Planet planet, double mass)
{
return mass * SurfaceGravity(planet);
}
private static PlanetData GetPlanetData(Planet planet)
{
if (!planetMap.ContainsKey(planet))
throw new ArgumentOutOfRangeException("planet", "Unknown Planet");
return planetMap[planet];
}
#region Nested type: PlanetData
public class PlanetData
{
public PlanetData(double mass, double radius)
{
Mass = mass;
Radius = radius;
}
public double Mass { get; private set; }
public double Radius { get; private set; }
}
#endregion
}
}