Using reflection I have a tool that gets the properties of a class:
foreach (MemberInfo member in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
WriteValue(streamWriter, member.Name);
}
Is there a way to ask "GetProperties" to return MemberInfo's in the order they are defined in the class. I seriously doubt it, but thought I'd ask.
class Person
{
public int Id { get; set; }
public int Age { get; set; }
}
I'd like to get MemberInfo's in this order then: Id, Age
[Caution: use at your own discresion as these are obviously Microsoft's impl details, which may change in future releases]
Update: Mono seems to work too
I've observed consitent behaviour using MS compilers since v3.5 when I stumbled upon this:
using System;
using System.Linq;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
typeof(Test).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.OrderBy(member => member.MetadataToken).ToList()
.ForEach(member => Console.WriteLine(member.Name));
Console.ReadLine();
}
}
public class Test
{
public int SecondProperty { get; set; }
public int FirstProperty { get; set; }
}
}
No, for auto-properties there isn't. You can get methods in order of declaration using debug symbols, and since property getters are methods, you can (with some work) obtain a list of properties with explicit getters (or setters) in order of declaration, but the getters of auto-properties have no source code and thus no debug symbols to indicate their location. As for CLI metadata, the compiler is not obliged to put them in order of declaration, and as reflection relies exclusively on metadata, it cannot be used for this purpose.
Related
I am working on an application that stores data in the ConfigurationManager.AppSettings file, and I am wanting to implement it in a different way than how I do right now. Currently, I have an interface (see below) that each class with saveable traits needs to implement, then call the static save methods from my Config class (example below). I don't like the coupling between my Config class and the class with the saveable data, so my ideal would be to have an attribute that indicates a property should be saved. Then, instead of calling the SaveData or LoadData functions in my manager class, I would call a function that sets/saves all the attributed properties. This seems similar to how [Serializeable] works in default C#, so I imagine it's possible somehow. However, most of my searches have been fruitless. Any ideas on how to implement something like this?
Interface
Example
Reflection is what you're looking for.
Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them.
Assuming that you're only interested in properties, you can use typeof or GetType to get an instance of System.Type. You can then call GetProperties to get an IEnumerable<PropertyInfo>. PropertyInfo has an Attributes property that you can use to retrieve the attributes for that property. You can also use an instance of PropertyInfo to retrieve the value of the property.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
[AttributeUsage(AttributeTargets.Property)]
public class MyAttribute : Attribute
{
}
public class Foo
{
[My]
public string Bar { get; set; }
public string Baz { get; set; }
[My]
public string Id { get; set; }
}
public static class Utilities
{
public static IEnumerable<PropertyInfo> GetPropertiesWithMyAttribute(object obj)
{
return obj.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(pi => pi.CustomAttributes.Any(ca => ca.AttributeType == typeof(MyAttribute)));
}
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo()
{
Bar = "Bar_Value",
Baz = "Baz_Value",
Id = "Id_Value"
};
foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
{
Console.WriteLine($"{pi.Name}: {pi.GetMethod.Invoke(foo, null).ToString()}");
}
foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
{
pi.SetMethod.Invoke(foo, new object[] { $"{pi.Name}_Value_Reflection" });
}
Console.WriteLine(foo.Bar);
Console.WriteLine(foo.Baz);
Console.WriteLine(foo.Id);
Console.ReadKey();
}
}
Of course, this example only string properties. You're going to have to figure out some way to deal with properties that aren't strings; for example you haven an ObservableCollection in your example.
After compiling and running the program with:
class Person
{
private string surname;
public string Name { get; set; }
public string Surname
{
get { return surname;}
set
{
surname = value;
}
}
}
One can see, from the image linked, there is no "name" private field shown.
Is it just Visual Studio not recognizing it, or is there something else going on?
I have read numerous times things like "As for your two C# examples, one is simply syntactic sugar for the other." or "A backing field will be created when compiling.".
What's the catch?
The backing field isn't shown to you by the debugger. That doesn't mean it isn't there, it simply means that the designers of the debugger didn't feel it was important for people debugging code to be looking at private backing fields of auto properties, given that they can simply access the data through the property itself.
With a help of reflection you can get a report what's actually going on:
using System.Reflection;
...
var fields = typeof(Person)
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Select(field => field.Name);
Console.Write(string.Join(Environment.NewLine, fields));
And get
surname
<Name>k__BackingField
As you can see the compiler has created the backing field <Name>k__BackingField for the auto property
I compiled a project with this silly class:
using System;
namespace ApagueMe
{
public class Class1
{
public string Asdf { get; set; }
}
}
Then, i opened the generated DLL in .NET Refletor. Look at the result:
public class Class1
{
// Fields
[CompilerGenerated, DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string <Asdf>k__BackingField;
// Properties
public string Asdf
{
[CompilerGenerated]
get
{
return this.<Asdf>k__BackingField;
}
[CompilerGenerated]
set
{
this.<Asdf>k__BackingField = value;
}
}
}
I've refactored code like this:
public string CamelCASE { get; set; }
to:
public string CamelCase {get; set; }
only do discover that the input XML contains the former casing (let's call it a shouting camel). I have no control over how the XML document is produced. Nor do I burn of desire to retract my changes.
I'd like to map the loud camel property to a softly speaking one.
I've tried XmlElement and XmlMapping but to no greater success. A googling gave me only hits on how to map stuff to attributes, along lines of this post. However, I need only something like <LoudCAMEL> to be deserialized to a property public string QuietCamel.
Is there a smooth way to do so?
Edit
After adding the attribute as follows:
using System.Collections.Generic;
using System.Xml;
public class Beep : SuperBeep
{
private readonly BeepType _a;
public Beep() { _a = BeepType.SomeSome; }
public Beep(BeepType input) { _a = input; }
~Beep() { }
public override void Dispose() { }
public BeepType Aaa { get { return _a; } }
[XmlElement("CamelCASE")]
public bool CamelCase { get; set; }
}
I can see the red, wavy highlight telling me Cannot access constructor 'XmlElement' here due its protection level. When I compile, though, I get the IDE crying out loud that 'System.Xml.XmlElement' is not an attribute class.
Frankly, I'm a bit confused by the suggestion to use attributes (this is targeting .NET 2.0), since I was under the impression that attributing wasn't available to .NET prior to version 3.5. Am I mistaken?
[XmlElement("CamelCASE")]
public string CamelCase { get; set; }
should be all you need, if you are keeping the shouty name in the xml. If you want to use the quieter name in new xml, but allow the old name to still work, it gets more complicated. You could use:
public string CamelCase { get; set; }
[XmlElement("CamelCASE"), Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public string CamelCaseLegacy {
get { return CamelCase; }
set { CamelCase = value; }
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeCamelCaseLegacy() { return false; }
When serializing, the CamelCase property will serialize to <CamelCase>, and the CamelCaseLegacy element will be ignored due to the ShouldSerialize* method. However, when deserializing, the CamelCaseLegacy property will be used whenever <CamelCASE> is seen. We then map this value back to the CamelCase property.
You are referring to the wrong namespace.
Remove
using System.Xml;
and add
using System.Xml.Serialization;
I have a public class(TargetContainerDto) that has 2 internal properties. An enum and a type that contains a value from that enum.
I'm trying to unit test the type, but I'm having problems.
internal enum TargetContainerType
{
Endpoint,
Group,
User,
UserGroup
}
internal TargetContainerType Type { get; set; }
This is my reflection code in my test class
public void setType(TargetContainerDto t, int val)
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo pi = t.GetType().GetProperty("Type", bf);
pi.SetValue(t, val, null);
}
public TargetContainerDto setTypeTo(TargetContainerDto t, int val)
{
setType(t, val);
return t;
}
TargetContainerDto has more properties than Type, but they are public so testing them is fine. The iconURL is a string defined in TargetContainerDto depending on what the type is. Here is my Testmethod:
public void DefaultSubGroupIcon()
{
var o1 = new TargetContainerDto
{
Id = 1234,
DistinguishedName = "1.1.1.1",
SubGroup = "test",
};
setType(o1, 3);
Assert.AreEqual(o1.IconUrl, "/App_Themes/Common/AppControl/Images/workstation1.png");
}
I call setTypeTo in test method when I need to set the typevalue, but I'm getting a MethodAccessException. I think it's because I don't have access to the enum. How can I access the enum through reflection?
Thanks
Mark your assembly with the InternalsVisibleTo attribute and you don't need to use reflection in your test dll.
e.g. in the AssemblyInfo.cs file in your application dll add the following line:
[assembly:InternalsVisibleTo("TestAssembly")]
see here for more details.
You asking the wrong question. A better question would be:
How do I stop testing internal state of the class?
But, if you utterly need this, there are couple of ways described in this relevant SO answer
I agree with other comments that you should try to redesign to avoid testing internal state, however I did try your code and it works fine for me (.Net 4 on VS2012).
My class library under test looks like this:
using System;
namespace ClassLibrary
{
internal enum TargetContainerType
{
Endpoint,
Group,
User,
UserGroup
}
public class TargetContainerDto
{
internal TargetContainerType Type
{
get;
set;
}
public void Print()
{
Console.WriteLine(Type);
}
}
}
And the test program (a Console app) looks like this:
using System;
using System.Reflection;
using ClassLibrary;
namespace Demo
{
internal class Program
{
private static void Main(string[] args)
{
var test = new TargetContainerDto();
setType(test, 1);
test.Print();
}
public static void setType(TargetContainerDto t, int val)
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo pi = t.GetType().GetProperty("Type", bf);
pi.SetValue(t, val, null);
}
}
}
This prints out Group, as expected. If we can identify the differences between this and your actual code, we may be able to find the problem.
Can some one explain to me why the GetProperties method would not return public values if the class is setup as follows.
public class DocumentA
{
public string AgencyNumber = string.Empty;
public bool Description;
public bool Establishment;
}
I am trying to setup a simple unit test method to play around with
The method is as follows and it has all the appropriate using statements and references.
All I'm doing is calling the following but it returns 0
PropertyInfo[] pi = target.GetProperties(BindingFlags.Public | BindingFlags.Instance);
But if I setup the class with private members and public properties it works fine.
The reason I didn't setup up the the class the old school way was because it has 61 properties and doing that would increase my lines of code to at least triple that. I would be a maintenance nightmare.
You haven't declared any properties - you've declared fields. Here's similar code with properties:
public class DocumentA
{
public string AgencyNumber { get; set; }
public bool Description { get; set; }
public bool Establishment { get; set; }
public DocumentA()
{
AgencyNumber = "";
}
}
I would strongly advise you to use properties as above (or possibly with more restricted setters) instead of just changing to use Type.GetFields. Public fields violate encapsulation. (Public mutable properties aren't great on the encapsulation front, but at least they give an API, the implementation of which can be changed later.)
Because the way you have declared your class now is using Fields. If you want to access the fields trough reflection you should use Type.GetFields() (see Types.GetFields Method1)
I don't now which version of C# you're using but the property syntax has changed in C# 2 to the following:
public class Foo
{
public string MyField;
public string MyProperty {get;set;}
}
Wouldn't this help in reducing the amount of code?
I see this thread is already four years old, but none the less I was unsatisfied with the answers provided. OP should note that OP is referring to Fields not Properties. To dynamically reset all fields (expansion proof) try:
/**
* method to iterate through Vehicle class fields (dynamic..)
* resets each field to null
**/
public void reset(){
try{
Type myType = this.GetType(); //get the type handle of a specified class
FieldInfo[] myfield = myType.GetFields(); //get the fields of the specified class
for (int pointer = 0; pointer < myfield.Length ; pointer++){
myfield[pointer].SetValue(this, null); //takes field from this instance and fills it with null
}
}
catch(Exception e){
Debug.Log (e.Message); //prints error message to terminal
}
}
Note that GetFields() only has access to public fields for obvious reasons.
As mentioned, these are fields not properties. The property syntax would be:
public class DocumentA {
public string AgencyNumber { get; set; }
public bool Description { get; set; }
public bool Establishment { get; set;}
}