Make this reflection method call typesafe - c#

class CustomerMessage
{
private string name;
private Dictionary<MethodBase, object> changeTrackingMethods =
new Dictionary<MethodBase, object>();
public int Id { get; set; }
public string Name {
get { return this.name; }
set
{
this.name = value;
this.PropertyChanged("SetName", value);
}
}
private void PropertyChanged(string behaviorMethod, object value)
{
var method = typeof(Customer).GetMethod(behaviorMethod);
this.changeTrackingMethods.Add(method, value);
}
public void ApplyChanges(Customer c)
{
foreach (var changedProperty in this.changeTrackingMethods)
changedProperty.Key.Invoke(c, new object[] {
changedProperty.Value
});
}
}
As you can see I am tracking the changes on this incoming message, to run the changes on another object. The method to run is passed to PropertyChanged as a string. Does anyone have a tip how I can make this type safe?

Something like this?
class CustomerMessage
{
private string name;
private List<Action<Customer>> changeTrackingMethods =
new List<Action<Customer>>();
public int Id { get; set; }
public string Name {
get { return this.name; }
set
{
this.name = value;
this.changeTrackingMethods.Add(c => { c.SetName(value) });
}
}
public void ApplyChanges(Customer c)
{
foreach (var action in this.changeTrackingMethods)
{
action(c);
}
}
}

So you want to avoid passing the method name as a string? Why not get the MethodBase object in the setter?
public string Name {
get { return this.name; }
set
{
this.name = value;
this.PropertyChanged(typeof(Customer).GetMethod(behaviorMethod), value);
}
}
private void PropertyChanged(MethodBase method, object value)
{
this.changeTrackingMethods.Add(method, value);
}

Instead of storing the "operation that needs to be done" as a pair of method and an argument that should be passed to it using Reflection, you can store a delegate that should be executed. The simplest way to do this is to store a list of type List<Action<Customer>> - then in the ApplyChanges method, you can iterate over the list and run all the actions.
In case you're not using .NET 3.5 and C# 3.0 (which defines a generic delegate Action and supports lambda expressions), you can still write this in C# 2.0:
// you can define a delegate like this
delegate void UpdateCustomer(Customer c);
// and you could use anonymous methods
// (instead of more recent lambda expressions)
list.Add(delegate (Customer c) { c.SetName("test"); });
EDIT: It looks like I was slower with writing the code, but I'll keep this here as an explanation - the solution by 'dtb' does exactly what I described.

Related

Force use members over fields

Is there a way to force usage of properties instead of private backing fields?
For example:
//field
private string str;
// property
public string Str
{
get { return this.str; }
set { this.str = value; DoSomething(); }
}
Both members need to have read rights however only property should have write rights. How to achive that?
EDIT: I was talking about access rights inside the class. Not from outside.
I'm assuming the reason that you don't want to be able to write directly to str within the class is because DoSomething is tightly coupled to its value changing. So to deal with that, use separation of concerns principles: create an internal class and make it solely responsible for ensuring that coupling is maintained:
internal class StrDoSomethingCoupler
{
private readonly Action _doSomething;
private string str;
public StrDoSomethingCoupler(Action doSomething)
{
_doSomething = doSomething;
}
public string Str
{
get { return _str; }
set { _str = value; _doSomething(); }
}
}
public class SomeClass
{
private readonly StrDoSomethingCoupler _coupler =
new StrDoSomethingCoupler(DoSomething);
...
public string Str
{
get { return _couple.Str; }
set { _coupler.Str = value; }
}
}
Although not clear this is a good question. Let me rephrase it.
Class A
{
//field
private string _str;
// member
public string Str
{
get { return _str; }
set { _str = value; DoSomething(); }
}
public void SomeMethod()
{
_str = "Dont access like this";
Str= "Should access only like this";
}
}
Sadly the answer is No, you cannot restrict the access of _str within Class A. Its only a coding practice you should follow, no inbuilt language feature that supports it. Reference - Blocking access to private member variables? Force use of public properties?
There is a problem that I can see in the sample code. You are doing two things within the setter of Str.
i.e. set { _str = value; DoSomething(); } is a bad practice(Although some places its unavoidable, like NotifyPropertyChanged() in wpf).
So don't do that, better change that logic by separating DoSomething() from Str.set. Something like
Class A
{
//field
private string _str;
// member
public string Str
{
get { return _str; }
private set { _str = value; }
}
private void DoSomething()
{
..
..
}
public void UpdateStrAndDoSomething(string strValue)
{
Str = strValue;
DoSomething();
}
}
private string _str;
public string Str
{
get { return _str; }
private set { _str = value; DoSomething();
}

Getting property values from a static class using reflection

I have a class that is used for storing user data to a file. It works well, but can't really be placed into a PCL library easily. Outside of the PCL, it's all fine.
The class looks like this
public static class UserData
{
public static object GetPropertyValue(this object data, string propertyName)
{
return data.GetType().GetProperties().Single(pi => pi.Name == propertyName).GetValue(data, null);
}
public static object SetPropertyValue<T>(this object data, string propertyName, T value)
{
data.GetType().GetProperties().Single(pi => pi.Name == propertyName).SetValue(data, value);
return new object();
}
private static string pUserSettingsFile;
private static UserSettings userSetting;
public static bool AccountEnabled
{
get
{
return UserSettings.account_enabled;
}
set
{
UserSettings settings = UserSettings;
settings.account_enabled = value;
UserSettings = settings;
}
}
public static UserSettings UserSettings
{
get
{
if (userSetting == null)
{
if (File.Exists(UserSettingsFile))
{
userSetting = Serializer.XmlDeserializeObject<UserSettings>(UserSettingsFile);
}
else
{
userSetting = new UserSettings();
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
return userSetting;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value is null!");
}
userSetting = value;
if (File.Exists(UserSettingsFile))
{
File.Delete(UserSettingsFile);
}
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
public static string UserSettingsFile
{
get
{
if (string.IsNullOrEmpty(pUserSettingsFile))
{
pUserSettingsFile = Path.Combine(GroupShootDroid.Singleton.ContentDirectory, "UserSettings.xml");
}
return pUserSettingsFile;
}
}
#endregion
}
public class UserSettings
{
public bool account_enabled { get; set; }
public string address { get; set; }
public string country { get; set; }
}
It's not rocket science, but does what I need it to do.
What I'm trying to do is use the Get/SetPropertyValue methods to return or set any of the properties within the class.
Currently, to access the Get/SetPropertyValue methods I'm using this
public string GetStringValue(string valToGet)
{
string rv = (string)UserData.GetPropertyValue(valToGet);
return rv;
}
public void SetStringValue(string name, string val)
{
UserData.SetPropertyValue(name, val);
}
On compiling though, the GetPropertyValue method is giving an error that No overload for method GetPropertyValue takes 1 argument with the SetPropertyValue complaining that there isn't an overload that takes 2
I'm not sure that the code I'm using will do what I need it to do (from what I've read on here it should be), but I'm more perplexed as to why the errors are showing.
Is there a better way to do what I'm trying to do? The application is a Xam.Forms app, so the PCL accesses the class through an interface using injection.
You are defining extension method, you need an instance of the class to call them:
var o = new Object();
string rv = (string)o.GetPropertyValue(valToGet);
// or, but no sure
string rv = (string)UserData.GetPropertyValue(o, valToGet);
or more probably in your case:
public string GetStringValue(string valToGet)
{
string rv = (string)this.GetPropertyValue(this, valToGet);
//or
//string rv = (string)UserData.GetPropertyValue(this, valToGet);
return rv;
}
I think you're getting confused between the UserData class and the object class. Your extension methods extend object.

Is there a wa to call a method immedietely after object instantiation?

public class Foo
{
public Foo(){ }
//One of many properties
//set up in the same way
private String _name;
public String Name
{
get { return _name; }
set {
_name = value;
//code that is important to run
//only after the objects initial creation
}
}
private int _id;
public int ID
{
get { return _id; }
set {
_id = value;
//code that is important to run
//only after the objects initial creation
}
}
public void Win()
{
//clean up method that wouldn't be needed
//if I used optional parameters because
//i would be able to set _name (and all the
//other private properties directly without
//using the public Set
}
}
How do I call a method automatically after this kind of object creation in c#
Foo ko = new Foo() {
ID = 4,
Name = "Chair"
};
ko.Win(); // <-- Want this to be called automatically inside the class
There is no method that automatically called after some random set of properties is set (Which is what initialization is translated to...)
var foo = new Foo { Name = "bar" };
Is actually shortcut to:
var foo = new Foo();
foo.Name = "bar";
When written in second form one would not expect any magical method to be called after foo.Name assignment.
You options:
if you have some information that need to be set on property change - just make it a property and write code in set part of it.
if you must have particular set of properties configured before object is considered "created" constructor arguments is one reasonable way to enforce it.
you can also implement builder pattern that allow you to delay final construction (or use some other factory method that forces setting parameters before final object creation.
Sample of code with builder pattern:
var foo = new FooBuilder { Name = "bar" }
.Build();
add the Win() to the constructor. Call/put inside the constructor.
public Foo(string value, string value2) {
Value = value;
Value2 = valu2e;
Win();
}
This is the constructor. Set it manually.
Well if you are always setting ID and the Name how about this?
private string _Name;
public string Name
{
get { return _Name; }
set {
_Name = value;
this.Win();
}
}
Win function will always called after you set a value on the name or you can do this for ID that's your choice!
Not the most scalable solution but why not try this:
public class Foo
{
public int ID { get; set; }
public String Name { get; set; }
public Foo()
{
}
public Foo( int id )
{
// Win()
ID = id;
// Win()
}
Public Foo( string name )
{
// Win()
Name = name;
// Win()
}
public Foo( int id, string name )
{
// Win()
ID = id;
Name = name;
// Win()
}
public void Win()
{
//Do Stuff that would go into the constructor
//if I wanted to use optional parameters
//but I don't
}
}
You can call Win before or after setting the properties.

Assigning fields dynamically

I have set of properties as follows:
public string Foo1 {set;get;}
public string Foo2 {set;get;}
public string Foo3 {set;get;}
public string Foo4 {set;get;}
public string Foo5 {set;get;}
public string Foo6 {set;get;}
public string Foo7 {set;get;}
public string Foo8 {set;get;}
public string Foo9 {set;get;}
......
public string Foo50 {set;get;}
then i m iterating through a collection as follows:
foreach(var element in sortedCollection.Keys){
if(element != null)
// in this block I would like to assign the element to the properties above
// ex:
foo?? = sortedCollection[element];
// ?? need to be replaced by index.
}
Is there an easy way to do this?
I think a better design would be:
public List<string> Foos { get; private set; }
If you can't change it, you could probably do something like:
var type = typeof(MyCalss);
int index = 1;
foreach (var key in sortedCollection.Keys)
{
var value = sortedCollection[key];
var prop = type.GetProperty("Foo" + index);
if (prop != null) prop.SetValue(this, value, null);
index++;
}
... of course with some error handling, and where this assumes this is a method within your class. Can you determine an index based on the values in your sortedCollection?
you can use reflection and do it in a loop:
for ( int i = 1 ; i < 51 ; i++)
this.GetType().GetProperty(string.Format("Foo{0}",i)).SetValue(this,desiredValue,null);
but i think i'll recommend using indexers
http://msdn.microsoft.com/en-us/library/2549tw02%28v=vs.80%29.aspx
You can do what you want by:
Using a for loop instead of foreach. This way you can operate with the current index.
Using reflections. You can get a list of properties for your class and access them dynamically. For example, see Type.GetProperties.
But why don't you just use a List<string> Foos instead of lots of properties?
You should use reflection.
this.GetType().GetProperty("Foo" + i).SetValue(this, sortedCollection[element], null);
Two things though:
GetProperty's cost is not null. So if you're doing this a lot of times, you might want to store the result of GetProperty in some field and then use this field in your foreach.
If your properties are really named Something1, Something2, etc..., then you may have a design flaw you may want to correct before doing this (replace all you string members with one List).
You need to use reflection (Type.GetProperty()) to get the property and set it's value.
Assuming that the properties are defined in class called MyClass:
foreach(var element in sortedCollection.Keys){
if(element != null)
// in this block I would like to assign the element to the properties above
// ex:
//foo?? = sortedCollection[element];
// not sure how you are getting the index here, may be you need to use for loop
PropertyInfo pi = typeof(MyClass).GetProperty("Foo" + index);
// ?? need to be replaced by index.
if (pi != null)
{
pi.SetValue(<object of MyClass>, sortedCollection[element], null);
}
}
void Main()
{
var foo = new Foo();
foo[1] = "Foo1";
//foo.Dump();
}
public class Foo
{
public string Foo1 {set;get;}
public string Foo2 {set;get;}
public string Foo3 {set;get;}
public string Foo4 {set;get;}
public string Foo5 {set;get;}
public string Foo6 {set;get;}
public string Foo7 {set;get;}
public string Foo8 {set;get;}
public string Foo9 {set;get;}
public string this[int index]
{
get
{
return getPropertyValue(index);
}
set
{
setPropertyValue(index, value);
}
}
private void setPropertyValue(int i, string value)
{
var propi = this.GetType().GetProperty("Foo" + i);
if (propi != null)
propi.SetValue(this,value,null);
}
private string getPropertyValue(int i)
{
var propi = this.GetType().GetProperty("Foo" + i);
if (propi != null)
return (string)propi.GetValue(this, null);
return null;
}
}
I would actually use reflection, or if this is called a lot, make a dynamic method and ILEmit to do it (much faster at runtime than reflection).
However just to suggest something different, you could change the class containing the Foo* properties to have each getter/setter read from an indexed list:
public class FooOfDoom
{
public string[] Foos = new string[2];
public string Foo1
{
set { Foos[0] = value; }
get { return Foos[0]; }
}
public string Foo2
{
set { Foos[1] = value; }
get { return Foos[1]; }
}
}
Then your class doesn't really change, as far as its contract with all the other code, since the properties are still there, but now you can assign right to Foos instead of through each individual property.
Again, in reality I would actually use a DynamicMethod if I was doing it myself.
Personally, I disagree with most of the other posters here. I think the use of reflection should be limited to those situations where it is really called for (object inspection, certain GUI situations, etc). In this case, with just a little more typing, it is possible to write a strongly-typed program and still do what you want. I'll offer two alternatives. Both alternatives will offer the ability to access your properties by name as well as by index.
In the first alternative, I'll assume that we are allowed to change the definition of your properties. In the second alternative, I'll assume that those definitions must remain unchanged.
The first alternative moves the data to a separate array, adds helper methods to access the data by index, and alters the properties to use the helper methods:
private class Version1 {
private readonly string[] underlyingData=new string[50];
public string Foo1 { get { return ReadFoo(1); } set { SetFoo(1, value); } }
public string Foo2 { get { return ReadFoo(2); } set { SetFoo(2, value); } }
public string Foo3 { get { return ReadFoo(3); } set { SetFoo(3, value); } }
//......
public string Foo50 { get { return ReadFoo(50); } set { SetFoo(50, value); } }
private string ReadFoo(int index) {
return underlyingData[index-1]; //1-based indexing
}
private void SetFoo(int index, string value) {
underlyingData[index-1]=value; //1-based indexing
}
}
The second alternative leaves the property definitions unchanged, and two static arrays of delegates representing the reading and writing function of those properties.
private class Version2 {
private static readonly Func<Version2, string>[] readers=new Func<Version2, string>[] {
c => c.Foo1,
c => c.Foo2,
c => c.Foo3,
//......
c => c.Foo50,
};
private static readonly Action<Version2, string>[] writers=new Action<Version2, string>[] {
(c,v) => c.Foo1=v,
(c,v) => c.Foo2=v,
(c,v) => c.Foo3=v,
//......
(c,v) => c.Foo50=v,
};
public string Foo1 { set; get; }
public string Foo2 { set; get; }
public string Foo3 { set; get; }
//......
public string Foo50 { set; get; }
private string ReadFoo(int index) {
return readers[index-1](this); //1-based indexing
}
private void SetFoo(int index, string value) {
writers[index-1](this, value); //1-based indexing
}
}

Properties exposing array elements in C#

I want to create a property in C# that sets or returns an individual member of an array. Currently, I have this:
private string[] myProperty;
public string MyProperty[int idx]
{
get
{
if (myProperty == null)
myProperty = new String[2];
return myProperty[idx];
}
set
{
myProperty[idx] = value;
}
}
However, I get the following compile error:
Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type.
How about this: write a class that does one thing and one thing only: provide random access to elements of some underlying indexed collection. Give this class a this indexer.
For properties that you want to provide random access to, simply return an instance of this indexer class.
Trivial implementation:
public class Indexer<T>
{
private IList<T> _source;
public Indexer(IList<T> source)
{
_source = source;
}
public T this[int index]
{
get { return _source[index]; }
set { _source[index] = value; }
}
}
public static class IndexHelper
{
public static Indexer<T> GetIndexer<T>(this IList<T> indexedCollection)
{
// could cache this result for a performance improvement,
// if appropriate
return new Indexer<T>(indexedCollection);
}
}
Refactoring into your code:
private string[] myProperty;
public Indexer<string> MyProperty
{
get
{
return myProperty.GetIndexer();
}
}
This will allow you to have as many indexed properties as you want, without needing to expose those properties with the IList<T> interface.
You must use this as the property name for indexers.
C# allows only one indexed property per class, so you are forced to use this.
You can use it this way:
private string[] myProp;
public string[] MyProp
{
get
{
if (myProp == null)
{
myProp = new String[2];
}
return myProp;
}
set
{
myProp = value;
}
}
And it's possible to acces myProp[1] as MyProp[1] for Example
Exposing your array through a read-only property might cover your needs. Since you don't want to allow other code to assign the array as such, there is no need for a public setter:
private string[] myProperty;
public string[] MyProperty
{
get
{
if (myProperty == null)
{
myProperty = new String[2];
}
return myProperty;
}
}
Then you can write code as such:
theObject.MyProperty[1] = "some string";
...but you cannot replace the array itself:
theObject.MyProperty = new string[2]; // will not compile
An option is to recode it as follows:
private string[] myProperty = new string[2];
public string[] MyProperty
{
get
{
return myProperty;
}
set
{
myProperty = value;
}
}
It'll compile, but it does have its own set of issues (fxCop will yell about it, but it can lead you to other options).
You could do something like this:
class Indexers
{
private string[] _strings = new [] {"A","B"};
private int[] _ints = new[] { 1, 2 };
public string[] Strings
{
get{ return _strings;}
}
public int[] Ints
{
get{ return _ints;}
}
}
class Program
{
static void Main(string[] args)
{
Indexers indexers = new Indexers();
int a1 = indexers.Ints[0];
string a2 = indexers.Strings[0];
}
}
C# provides no built-in mechanism to create indexed properties. You can use a class-level indexer (using this[int index] notation), but nothing like this on a property level.
One option is to create a helper class with an indexer and use this class as the property type. See an example on MSDN.
First, in-field declaration avoids excess check:
private string[] myProperty = new string[2];
You can implement several indexers via overloading by input type:
public string this[int index]
{
get
{
return myProperty[index];
}
set
{
myProperty[index] = value;
}
}
public object this[object a, object b] // different input type(s) (and different return type)
{
get
{
// do other stuff
}
}
You need to use an indexer. It works a little differently. See example:
public class Node
{
public Node this[int offset]
{
get { return localList[offset]; }
}
}
Note: You are allowed only one indexer per class. The reason is that it is too confusing to the compiler as to the meaning, so you only are allowed one.
You can also do this:
private static int[] _widget = new int[Counter];
public static int [] Widget
{
get { return _widget; }
set { _widget = value; }
}
...
for (int i = 0; i < MyClass.Counter; i++)
{
MyClass.Widget[i] = i;
}
...
double _newWidget5 = MyClass.Widget[5];
// and so on...

Categories