I have a requirement to extract all public read-write properties that are not enumerable, unless they are a string. This is currently done by refelction and wondering if this can be done with FastMember.
I tried something like the code below but it doesn't do what I want. Can I do this with the current version of FastMember?
Cheers,
Berryl
protected void LoadCache(IHaveEditableStateProperties originator) {
var type = originator.GetType();
_accessor = TypeAccessor.Create(type);
var members = _accessor.GetMembers();
_editableState = new Dictionary<string, object>();
foreach (var member in members) {
if(member.Type == typeof(PropertyInfo)) {
_editableState.Add(member.Name, _accessor[originator, member.Name]);
}
}
}
...
}
As I understand it, member.Type as returned from FastMember is the return type of the property or method. It should never be PropertyInfo as you are checking for in your code. _accessor[originator, member.Name] should return the current value of the property.
Related
I have a class with custom enum:
public enum Capabilities{
PowerSave= 1,
PnP =2,
Shared=3, }
My class
public class Device
{
....
public Capabilities[] DeviceCapabilities
{
get { // logic goes here}
}
Is there a way using reflection to get the value of this field during runtime?
I tried the following but got null reference exception
PropertyInfo[] prs = srcObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo property in prs)
{
if (property.PropertyType.IsArray)
{
Array a = (Array)property.GetValue(srcObj, null);
}
}
EDIT: Thanks for your answers, what I really need is a way to get the values dynamically without the need to specify the enum type.
Something like:
string enumType = "enumtype"
var property = typeof(Device).GetProperty(enumType);
Is that possible?
The following should do what you desire.
var property = typeof(Device).GetProperty("DeviceCapabilities");
var deviceCapabilities = (Capabilities[])property.GetValue(device);
Note that the method Object PropertyInfo.GetValue(Object) is new in .NET 4.5. In previous versions you have to add an additional argument for the indices.
var deviceCapabilities = (Capabilities[])property.GetValue(device, null);
This should work:
var source = new Device();
var property = source.GetType().GetProperty("DeviceCapabilities");
var caps = (Array)property.GetValue(source, null);
foreach (var cap in caps)
Console.WriteLine(cap);
If you want to enumerate all the possible values of an Enum and return as an array then try this helper function:
public class EnumHelper {
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
}
Then you can simply call:
Capabilities[] array = EnumHelper.GetValues<Capabilities>();
If that isn't what you are after then I'm not sure what you mean.
You can try this
foreach (PropertyInfo property in prs)
{
string[] enumValues = Enum.GetNames(property.PropertyType);
}
Hope it helps.
I have a "settings" class, which has some properties for usability and to restrict set accessor. It seems easy while i had within ten items, but then their count was increased. I need some way to create these properties automatically, something like that:
foreach(var property in SettingsList)
{
_settings.AddAutoProperty(property);
}
It may have deal with reflection, but i can't get to efficient solution.
The properties definition:
public bool cbNextExcCount
{
get { return (bool)this.GetValueById("cbNextExcCount"); }
}
public bool cbSaveOnChangeExc
{
get { return (bool)this.GetValueById("cbSaveOnChangeExc"); }
}
public bool cbAutoIncrement
{
get { return (bool)this.GetValueById("cbAutoIncrement"); }
}
public bool cbRememberOnExit
{
get { return (bool)this.GetValueById("cbRememberOnExit"); }
}
...etc.
UPDATE
To summ up, i wrote the next code:
public IDictionary<string, object> Properties = new ExpandoObject();
private List<string> SettingsList = new List<string>
{
"cbNextExcCount",
"cbSaveOnChangeExc",
"cbAutoIncrement",
"cbRememberOnExit"
};
public void CreateProperties()
{
foreach (string SettingName in SettingsList)
{
Properties.Add(SettingName, () => this.GetValueById(SettingName));
}
}
But i have an error on () => this.GetValueById("cbNextExcCount")):
argument type 'lambda expression' is not assignable to parameter type 'object'.
I can store Func<bool>, but settings may have other type than bool and if i use Func, it's get a bit more complicate to call.
You can't create auto-properties, but you can use an ExpandoObject.
I'm not sure if this is what you're looking for, because using expandos means using duck typing (i.e. dynamic programming).
ExpandoObject sample:
dynamic expando = new ExpandoObject();
expando.PropertyA = "Hello";
expando.PropertyB = "world!";
An interesting thing about expandos is that ExpandoObject implements IDictionary<string, object>, meaning that you can upcast any expando to this type and iterate over its added properties, which could be great for storing run-time created settings.
UPDATE
I was thinking more about a good solution and if SettingList is a custom class developed by yourself, maybe you can add a property called Custom to SettingList and add there settings that aren't added during design-time.
UPDATE 2
In your case, instead of storing the actual value of something, you could add Func<bool> to ExpandoObject's run-time settings:
IDictionary<string, object> settings = new ExpandoObject();
settings.Add("cbNextExcCount", () => this.GetValueById("cbNextExcCount"));
Actually, I don't know this scope in your code sample, but change this to anything that could be an instance of SettingList or whatever.
Once you've added run-time settings, you can type settings variable to dynamic typing in order to access properties like this:
dynamic allSettings = (dynamic)settings;
bool cbNextExcCount = allSettings.cbNextExcCount();
You can consider Expando Objects in System.Dynamic namespace. This article can be a good start.
Say I define a variable like this:
var o = new { RBI = 108, Name = "Roberto Alomar" };
I can do something like:
Console.WriteLine("{0}", o);
But if I try:
foreach (var i in o) {
Console.WriteLine("{0}", o[i]);
}
I get an error:
foreach statement cannot operate on variables of type 'AnonymousType#1' because 'AnonymousType#1' does not contain a public definition for 'GetEnumerator'
So how does it work under the hood? I'd think that a method for turning an object into a string would have to loop through all the properties to accomplish the task. Is there some special method that allows this to happen, or am I misunderstanding how this works?
How does it work under the hood? I'd think that a method for turning an object into a string would have to loop through all the properties to accomplish the task.
Your assumption is that the implementation of ToString is shared between all instances of all anonymous types; that, for example, there is some helper that is logically something like you would do in JavaScript:
var s = "";
for (property in this)
s += property + ":" + this[property];
This assumption is wrong; there is no single one-size-fits-all implementation of ToString for anonymous types. Rather, the compiler knows what all the properties of the anonymous method are and so it generates a brand-new custom implementation of ToString for every distinct anonymous type.
In C#, the foreach loop does not do what the for-in loop does in JavaScript. The C# loop enumerates the members of a collection. The JS loop enumerates the properties of an object.
If you want to enumerate the properties of an object in C# you can do that, it just takes a bit more work:
var s = "";
foreach (PropertyInfo propertyInfo in this.GetType().GetProperties())
s += propertyInfo.Name + ":" + propertyInfo.GetValue(this).ToString();
You cannot do that because anonymous types don't implements IEnumerable interface - it's not a collection just one object. You have to explicitly print the values.
Console.WriteLine("{0}", o.RBI);
Console.WriteLine("{0}", o.Name);
But step yourself back. Do you need anonymous type? Define your own custom type.
class MyType // give it more meaningful name
{
public int RBI { get; set;}
public string Name { get; set;}
}
All anonymous objects have the same methods. They can be compared to each other as long as they have the same named fields with the same types, they all have a ToString() implementation that will give the string as you can see. But they don't have an implementation of an enumerator. Why should they? It's not like Javascript in that sense where you can enumerate over the property names/indices/whatever because... it's C#, that's just not how it is. Why would you think any different?
If you wanted something to work similarly, fortunately we have implicitly typed variables and reflection to help us out there.
var obj = new { Foo = "asd", Bar = "add", Gar = "123" };
var adapter = PropertyAdapter.Create(obj);
foreach (var name in adapter)
Console.WriteLine("obj.{0} = {1}", name, adapter[name]);
public static class PropertyAdapter
{
public static PropertyAdapter<T> Create<T>(T obj)
{
return new PropertyAdapter<T>(obj);
}
}
public class PropertyAdapter<T> : IEnumerable<string>
{
private T obj;
public PropertyAdapter(T obj) { this.obj = obj; }
public override string ToString()
{
return obj.ToString();
}
public object this[string name]
{
get
{
return typeof(T).GetProperty(name).GetValue(obj, null);
}
}
public IEnumerator<string> GetEnumerator()
{
return typeof(T)
.GetProperties()
.Select(pi => pi.Name)
.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
When you do
Console.WriteLine("{0}", o);
What's really happening is a call to Object.ToString(), which is inherited and has a built-in implementation for anonymous types that prints the properties and values.
On the other hand,
foreach (var i in o) { .. }
Can't work, because o must be an IEnumerable (or IEnumerable<>)
EDIT: The equivalent of what your expecting Enumerating over the string that is printed when using WriteLine can be achieved (for explanatory purposes, and otherwise useless) by doing:
foreach (var i in o.ToString()) { .. }
However as Jeff Mercado points out, that is not what you seem to want (it won't iterate over the properties - only over the individual characters of the already-formatted string)
i've some classes and want to access their properties using index or something like
ClassObject[0] or better will be ClassObject["PropName"]
instead of this
ClassObj.PropName.
Thanks
You need indexers:
http://msdn.microsoft.com/en-us/library/aa288465(v=vs.71).aspx
public class MyClass
{
private Dictionary<string, object> _innerDictionary = new Dictionary<string, object>();
public object this[string key]
{
get { return _innerDictionary[key]; }
set { _innerDictionary[key] = value; }
}
}
// Usage
MyClass c = new MyClass();
c["Something"] = new object();
This is notepad coding, so take it with a pinch of salt, however the indexer syntax is correct.
If you want to use this so you can dynamically access properties, then your indexer could use Reflection to take the key name as a property name.
Alternatively, look into dynamic objects, specifically the ExpandoObject, which can be cast to an IDictionary in order to access members based on literal string names.
You can do something like this, a pseudocode:
public class MyClass
{
public object this[string PropertyName]
{
get
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
return pi.GetValue(this, null); //not indexed property!
}
set
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
pi.SetValue(this, value, null); //not indexed property!
}
}
}
and after use it like
MyClass cl = new MyClass();
cl["MyClassProperty"] = "cool";
Note that this is not complete solution, as you need to "play" with BindingFlags during reflection access if you want to have non public properties/fields, static ones and so on.
public string this[int index]
{
get
{ ... }
set
{ ... }
}
This will give you an indexed property. You can set any parameter you wish.
I'm not sure what you mean here, but I'll say that you have to make ClassObject some sort of IEnumirable type, like List<> or Dictionary<> to use it the way to aim for here.
I wrote a function that copies the properties of one class to another so make a copy of an object.
So something like
MyObject myObject = myOtherObject.MyCustomCopy(myObject)
where myObject and myOtherObject are of the same type. I do it by bascually doing
myObject.prop1 = myOtherObject.prop1
myObject.prop2 = myOtherObject.prop2
myObject.prop3 = myOtherObject.prop3
return myObject
I am pretty sure in the past I used a .NET object that automaticaly did this, by reflection I guess, but can't remember it ... or an I imagining that such a method exists?
Yes I'm aware of auto mapper but i was sure (not so much now) that there is a .NET object that does the job. Maybe not!
You may take a look at AutoMapper.
public static class ext
{
public static void CopyAllTo<T>(this T source, T target)
{
var type = typeof(T);
foreach (var sourceProperty in type.GetProperties())
{
var targetProperty = type.GetProperty(sourceProperty.Name);
targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
}
foreach (var sourceField in type.GetFields())
{
var targetField = type.GetField(sourceField.Name);
targetField.SetValue(target, sourceField.GetValue(source));
}
}
}
You should use AutoMapper it was built for this job.
System.Object.MemberwiseClone()
Try description in this link:
.NET Reflection - Copy Class Properties
This code should work for basic property types, not sure how it'll go for anything complex (lists, arrays, custom classes). Should be a starting point though:
public class MyClass
{
public int A { get; set; }
public string B { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
MyClass orig = new MyClass() { A = 1, B = "hello" };
MyClass copy = new MyClass();
PropertyInfo[] infos = typeof(MyClass).GetProperties();
foreach (PropertyInfo info in infos)
{
info.SetValue(copy, info.GetValue(orig, null), null);
}
Console.WriteLine(copy.A + ", " + copy.B);
}
I know the OP did not ask for a Type to another Type but my variant is one I use for DI in startup.cs for mismatches in configurations between cloud and local dev environment. My local class generally uses a Interface class behind the scenes to map the configurations. Then I use this method to copy properties where they match in name only. I am not checking property types since these are configurations. AutoMapper was suggested. I don't use AutoMapper because we are restricted by U.S. DOD to certain providers. Getting an ATO is hard enough just using .NET, we don't need any more grief.
using System.Linq;
public static class PropertyCopy
{
public static void CopyAllTo<T,T1>(this T source, T1 target)
{
var type = typeof(T);
var type1 = typeof(T1);
foreach (var sourceProperty in type.GetProperties())
{
foreach (var targetProperty in type1.GetProperties()
.Where(targetProperty => sourceProperty.Name == targetProperty.Name)
.Where(targetProperty => targetProperty.SetMethod != null))
{
targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
}
}
foreach (var sourceField in type.GetFields())
{
foreach (var targetField in type1.GetFields()
.Where(targetField => sourceField.Name == targetField.Name))
{
targetField.SetValue(target, sourceField.GetValue(source));
}
}
}
}
In very simple terms: As we know Classes are reference types in C#.NET i.e. when we create a object of a class such as
Customer C1=new Customer();
C1.Id=1;
C1.Name="Rakesh";
Then C1(Reference variable) is stored on memory stack and object new Customer() is stored on Heap.
Hence when we copy a class into another class which is basically your question you can do something like below:
Customer C2=C1;
Doing above will copy the C1 Reference variable into C2 But why I wrote about Stack and Heap because using C2 reference variable you can change the object properties being both C1 and C2 pointing to same object in HEAP.Something Like
C2.Id=1;
C2.Name="Mukesh";
Now if you will try to access C1.Name you will see it is changed to "Mukesh".
you can use JsonConvert like this:
string jsonString = JsonConvert.SerializeObject(MyObject);
MyClass object = JsonConvert.DeserializeObject<MyClass>(jsonString);