Given the following code;
public class CustomControl {
private object _dataItem;
public object DataItem {
get { return _dataItem; }
set { _dataItem = value; }
}
public void Update(ref string t) {
t = "test";
}
}
public class Consume {
public void Example() {
CustomControl ctrl = new CustomControl();
ctrl.DataItem = anyObject.anyProperty;
string prop = anyObject.anyProperty;
ctrl.Update(ref prop);
anyObject.anyProperty = prop;
}
}
How can I change it so that the DataItem property is itself a reference, allowing you to pre-emptively set it to point to a variable thus allowing you to call Update() without any parameters.
So the Consume class would then look similar to;
public class Consume {
public void Example() {
CustomControl ctrl = new CustomControl();
ctrl.DataItem = anyObject.anyProperty;
ctrl.Update();
// anyObject.anyProperty has been updated to "test"
}
}
So the assigment of anyObject.anyProperty is then handled internally within CustomControl
You need to store the act of setting something to a string, so store an Action<string>:
public class CustomControl {
public Action<string> SetData { get; set; }
public void Update() {
// TODO nullity check
SetData("test");
}
}
Then Consume would look like:
public class Consume {
public void Example() {
CustomControl ctrl = new CustomControl();
// store {the act of setting this property of this object to a string}
ctrl.SetData = s => anyObject.anyProperty = s;
ctrl.Update();
}
}
The Update call will set anyObject.anyProperty to test. Note that you are storing specifically the act of setting this property of the particular anyObject you refer to in the assignment to SetData.
To expand on the lambda: we want to create a value of type Action<string>, that is, a thing which takes a string and returns no result. Such a thing is going to be executable code. Prior to C# 3, to create a 'value' that was executable code, we would have had to do something like:
ctrl.SetData = delegate(string s) { someObject.SomeProperty = s; };
With this syntax it's more obvious that we're creating a method - it has a { } delimited body, it has statements in it, and it's clear there is a string parameter that is used by the body.
One thing achieved by lambda expressions in C# 3 is the ability to condense this down; loosely, the whole of
// not compilable code
delegate(parameters) { body; }
can be replaced with
// not compilable code
(parameters) => body;
and in the case where there's only one parameter
// not compilable code
parameter => body;
which is what we have here: the expression assigned to ctrl.SetData is a piece of behaviour that accepts a string (s) and sets anyObject.anyProperty to that string. The real power is in the way the C# compiler can work out the types to it know we're creating an Action<string>.
At first I didn't understand what you're trying to do. What you're looking for is the Adapter or Facade pattern. That is, you have an object with a particular interface, but you need to adapt it to a different interface or provide a simpler interface.
One way to implement these patterns is to use composition and delegate the new interface to methods on the existing interface.
public interface IUpdatable<U>
{
void Update( U newValue );
}
public abstract class CustomControl<T,U> : IUpdatable<U>
where T : Control
{
private T Control { get; set; }
protected CustomControl( T control )
{
this.Control = control;
}
public abstract void Update( U newValue );
}
public class TextBoxFacade : CustomControl<TextBox,string>, IUpdatable<string>
{
public TextBoxFacade( TextBox textbox ) : base(textbox) { }
public override void Update( string newValue )
{
this.Control.Value = newValue;
}
}
Related
I have a simple class that is intended for options of an winforms application. There should be a method that reset options to their default values. I know I can add a separate method to take care of this, but the code will be huge (If I add more options to the class) :
public SensorOptions()
{
ShowLabelMax = ShowLabelMin = ShowLabelAvr = ShowReceivedTextBox = true;
ChartMaxValue = 140;
ChartMinValue = -40;
ShowChartMinValue = ShowChartMaxValue = ShowChartAvrValue = ShowChartAvrLine = true;
LogFolder = Environment.SpecialFolder.MyDocuments.ToString();
LoggingEnabled = true;
}
public void ResetOptions()
{
this = new SensorOptions(); //can not do. 'this' is read-only
}
I mean I can copy/paste the code from constructor into ResetOptions() method. But is there any smarter ways to achieve this?
You cannot assign this because you may have references to this instance of your class in your program. If you could re-construct the object by re-assigning this, it would mean that all references to the old instance of the class become invalid.
No matter how many options you have in your class, you initialize each of them one or the other way (because you mention default value in your question - so you need to assign that default value somewhere at least once, probably in the constructor). Therefore, the solution to your problem is simple - move all initializers to the separate method and call it in the constructor, and then also call it every time you need to reset your options to their default values.
If any of your options are not assigned a default value explicitly, and use system default and you don't want to write option=default(optionType) for each option, you can use reflection to enumerate all fields/properties in that class and assign default values to them, like this:
public static object GetDefault(Type type)
{
if(type.IsValueType) return Activator.CreateInstance(type);
return null;
}
foreach(var field in this.GetType().GetFields())
field.SetValue(this, GetDefault(field.FieldType));
foreach(var prop in this.GetType().GetProperties())
prop.SetValue(this, GetDefault(prop.PropertyType));
Move all of the code from the constructor into the ResetOptions method, then in your constructor call the ResetOptions method. Your initialisiation code is only in one place then.
You have very simple architecture for your situation. In my opinion it would be better to apply a trick for this:
you have class for holding all your options (pseudo code):
class AllOptionsBackstage
{
public bool ShowLabelMax { get; set; }
public bool ShowLabelMin { get; set; }
public bool ShowLabelAvr { get; set; }
public AllOptionsBackstage()
{
// apply default values here
}
}
.....
class MyOptions
{
private AllOptionsBackstage _options;
public MyOptions()
{
Reset();
}
public bool ShowLabelMax
{
get{ return _options.ShowLabelMax; }
set{ _options.ShowLabelMax = value; }
}
public bool ShowLabelMin
{
get{return _options.ShowLabelMin;}
set{_options.ShowLabelMin=value; }
}
public bool ShowLabelAvr
{
get{ return _options.ShowLabelAvr;}
set{ _options.ShowLabelAvr = value; }
}
public void Reset()
{
_options = new AllOptionsBackstage(); // will reset all your options to default
}
}
I have the following issue related to reflection , I have a method which looks like this :
[TestMethod()]
public void steamAccess()
{
testRead = new TestRead();
SteamMap a = new SteamMap();
// Preparing the parameters of the CSV actions
a.writeMessageParams.UIItemEditText = TestContext.DataRow["SearchQuery"].ToString();
//Read and Execute the TestMethod
testRead.Read(a, TestContext);
}
This is a CodedUITest, SteamMap is a class (uiTest map).
WriteMessageParams is a class, actually the real method is WriteMessage but this class allows me to override the string that gets used into my tests by the WriteMessage method, and I plan to make this part of the code more dynamically in the Read method. :
a.writeMessageParams.UIItemEditText = TestContext.DataRow["SearchQuery"].ToString();
My problem happens in testRead.Read context as follows :
When this method is running I have access to all actions from the respective instance ( a in my case ) and if they are supposed to have to use a a.writeMessageParams.UIItemEditText context I know it, how I get the info isn't the problem, the problem is how to make the previously mentioned code to run dynamically as I have tried :
/* I've done this because I know that each method that is supposed to end up with Params, for example a method called WriteMessage, it's class is called WriteMessageParams*/
public void Read(object obj, TestContext testContext)
{
//simplified code
//trying to access/get to the current instance's WriteMessageParam class
Object testObj = obj.GetType().GetMember(subMethod.Code + "Param");
//null
MessageBox.Show(testObj.GetType().ToString());
// trying to access the UIItemEditText field ( which is declared as public) and modify it accordingly
FieldInfo subMethodField = testObj.GetType().GetField("UIItemEditText");
subMethodField.SetValue(testObj,testContext.DataRow[subMethod.CsvColumn].ToString());
}
I've had a read over this article and tried few things
https://msdn.microsoft.com/en-us/library/6z33zd7h%28v=vs.110%29.aspx
My problem is that I have the object of an instance and I try to access this object's class and modify that class's field .
I'd appreciate any help,
Thanks
Edit 1:
This is how the class I'm trying to access looks like :
public partial class SteamMap
{ //simplified to what classes/methods interest me
public virtual writeMessageParams writeMessageParams
{
get
{
if ((this.mwriteMessageParams == null))
{
this.mwriteMessageParams = new writeMessageParams();
}
return this.mwriteMessageParams;
}
}
public class writeMessageParams
{
#region Fields
/// <summary>
/// Type 'test' in text box
/// </summary>
public string UIItemEditText = "test";
#endregion
}
}
Edit 2 - I've tried by using GetNestedType, still no success....
Object testObj = obj.GetType().GetNestedType("writeMessageParams",BindingFlags.Public);
MessageBox.Show(testObj.GetType().ToString());
If I understand you, you have a class like
public partial class SteamMap
{
private writeMessageParams mwriteMessageParams ;
public virtual writeMessageParams writeMessageParams1
{
get
{
if ((this.mwriteMessageParams == null))
{
this.mwriteMessageParams = new writeMessageParams();
}
return this.mwriteMessageParams;
}
}
public class writeMessageParams
{
public string UIItemEditText = "test";
}
}
(your code doesn't compile because you have writeMessageParams both as the class and the property, so I have changed the property to writeMessageParams1)
And you want to change UIItemEditText, which you can do like
public void UpdateUI(object obj, string newValue)
{
var property = obj.GetType().GetProperty("writeMessageParams1");
var writeMessageParams1 = property.GetValue(obj);
var uiFld = wp.GetType().GetField("UIItemEditText");
uiFld.SetValue(writeMessageParams1, newValue);
}
which can be called like
SteamMap sm = new SteamMap();
Write(sm, "Hello");
The key is to use .GetProperty for the property and .GetField for the field.
I tried to search for an answer for this problem but could not find much, most probably because I do not know how to look for it properly, so here it goes. All help is very much appreciated.
With the base class that looks like
abstract public class Property
{
private String name;
public Property(String propertyName)
{
name = propertyName;
}
public String Name
{
get { return name; }
}
abstract public override String ToString();
}
And derived classes that look like
public class StringProperty : Property
{
private String value; // different properties for different types
public StringProperty(String propertyName, String value) : base(propertyName)
{
this.value = value;
}
public String Value // different signature for different properties
{
get { return value; }
}
public override String ToString()
{
return base.Name + ": " + value;
}
}
During runtime, the function receives a collection of "Property" objects. What do I need to do to be able to obtain the "Value" of each? Do I need to have a big if statement to query the type of each "Property" object? If not, is there a more elegant solution?
I tried to define an abstract "Value" property to be overridden but since the return types are different, it did not work. I also tried playing with shadowing the "Value" property, but I could not make it work. The idea of using an COM-like Variant does not sound very appropriate, either.
Thanks a lot in advance.
EDIT:
I should have added details as to what I am trying to do. The properties are displayed in a Winforms app. Different "TextBox"es represent different properties and are filtered for proper input (depending on the type). The updated values are read back and stored. The container object will be serialized into JSON and deserialized on an Android and iPhone client and eventually these values will be passed into a layer running native C++ code doing OpenGL stuff. I don't know in advance the kind of all needed properties so as the middleman, I wanted to make my code as robust as possible while being able to feed the OpenGL engine.
You can use a generic class:
public class AnyProperty<T> : Property
{
private T value;
// ... etc
I'd really recommend making the base class an Interface by now:
public interface IProperty
{
public String Name { get; }
}
public class Property<T> : IProperty
{
public Property(String name, T value)
{
Name = name;
Value = value;
}
public String Name { get; private set; }
public T Value { get; private set; }
public override String ToString()
{
return string.Format("{0}: {1}", Name, Value)
}
}
Here is sample usage:
var intProp = new Property<int> ("age", 32);
var strProp = new Property<string> ("name", "Earl");
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);
To make the construction even simpler, you could have a factory method:
public static Property<T> MakeProperty(string name, T value)
{
return new Property<T>(name,value);
}
var intProp = MakeProperty("age", 32);
var strProp = MakeProperty("name", "Earl");
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);
Not necessarily recommended, and a bit OT:
You could make it even funkier with an extension method:
public static Property<T> AsProp<T>(this T value, string name)
{
return new Property<T>(name,value);
}
var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");
You would have to simply use the object type. What are you trying to accomplish? The problem here isn't the structure of your classes, it's the function that receives the collection of Property objects. It's impossible to even cast something to an unknown type, since you don't know what type of variable it needs to be stored in.
So basically, your Property.Value property needs to be of type object. In your method that uses the Property objects, you need to do something with them, and what you're doing will decide how it should be structured. Are you printing values out? Have a *Value class inheriting from an abstract PropertyValue class and override ToString() to return an appropriate string represention.
I made a few changes to your sample code and got this result...
abstract public class Property
{
private readonly String _name;
public Property(String propertyName)
{
_name = propertyName;
}
public String Name
{
get { return _name; }
}
abstract public override String ToString();
}
public class StringProperty : Property
{
private readonly dynamic _value; // different properties for different types
public StringProperty(String propertyName, dynamic value)
: base(propertyName)
{
this._value = value;
}
public dynamic Value // different signature for different properties
{
get { return _value; }
}
public override String ToString()
{
return base.Name + ": " + _value;
}
}
static void Main(string[] args)
{
StringProperty sp = new StringProperty("A double", 3.444);
StringProperty sp2 = new StringProperty("My int", 4343);
StringProperty sp3 = new StringProperty("My directory", new DirectoryInfo("Some directory"));
StringProperty sp4 = new StringProperty("My null", null);
Console.WriteLine(sp);
Console.WriteLine(sp2);
Console.WriteLine(sp3);
Console.WriteLine(sp4);
}
}
Values are properly printed to the console in the expected way.
It would require a bit of a rethink, but have you considered using the dynamic type (introduced in .net4)
Doesn't really solve your problem, but sidespteps it.
Your properties can bascically just be a
Dictionary<String, dynamic>
, the gotcha is they don't get evaluated until runtime, so you get no compiler support for typing.
so given you want
int SomeValue = MyProperties[SomePropertyName] + 10;
So if
MyProperties[SomePropertyName] = 10; // all is good
if its 76.52 or Fred, the addition will throw an exception at the point it executes.
Code is much simpler and cleaner, no extra casting and the amount of scaffolding required is minimal, BUT, you'll need to unit test code that uses the dictionary extensively and religiously.
I need to access a property by an index or something similar. The reason why is explained in this already answered question. That answer uses Linq and I prefer something without that dependency. I have no control over the class.
public class myClass
{
private string s = "some string";
public string S
{
get { return s; }
}
}
class Program
{
static void Main(string[] args)
{
myClass c = new myClass();
// I would like something similar
// or same functionality
string s = c["S"];
}
}
As you have no control over the class you can use extension method and reflection to get property value by name:
static class ObjectExtensions
{
public static TResult Get<TResult>(this object #this, string propertyName)
{
return (TResult)#this.GetType().GetProperty(propertyName).GetValue(#this, null);
}
}
Usage:
class A
{
public string Z
{
get;
set;
}
public int X
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
A obj = new A();
obj.Z = "aaa";
obj.X = 15;
Console.WriteLine(obj.Get<string>("Z"));
Console.WriteLine(obj.Get<int>("X"));
Console.ReadLine();
}
}
use (EDIT - as per comment):
string s = c.GetType().GetProperty ("S").GetGetMethod().Invoke (c, null).ToString();
It gives you the value of the (public) property named S of the the instance c regardless of the type of c and doesn't use LINQ at all although I must admit that I don't see why LINQ should be a problem...
You can achieve the same thing by using a default property on your class and a collection. Provided that you will always want strings, you could use the Dictionary class as your default property.
Then in the constructor you could intialize myDictionary["s"] = "some string";
You could then use the myClass as a collection, so myClass["s"] would return "some string".
Reflection is usually an indicator that you haven't created an API to do the job you need, if you have the code to modify then I recommend you use the default property.
See this MSDN article:
I am working on a project where I need to queue up a number of property changes. Let say I have:
public class foo
{
string bar { get; set; }
int bar1 { get; set }
}
I want to have some code that looks like:
//Store value set actions in a queue
foo.SetValue(bar, "abc");
foo.SetValue(bar1, 123);
//Preview changes
foreach(Item change in foo.ChangeQueue)
{
Console.Write(change.PropertyName.ToString());
Console.Write(change.Value.ToString());
}
//Apply actions
foo.CommitChanges();
What is the best way to accomplish this?
You can use Dictionary<string,object> as ChangeQueue to store your values.
You can iterate as,
foreach(KeyValuePair<string,object> item in ChangeQueue){
Console.WriteLine(item.Key);// name of property
Console.WriteLine(item.Value); // value of property
}
public void SetValue(string name, object value){
PropertyInfo p = this.GetType().GetProperty(name);
// following convert and raise an exception to preserve type safety
ChangeQueue[name] = Convert.ChangeType(value,p.PropertyType);
}
public void ApplyChanges(){
foreach(KeyValuePair<string,object> item in ChangeQueue){
PropertyInfo p = this.GetType().GetProperty(item.Key);
p.SetValue(this, item.Value, null);
}
}
"Type-safe" version which uses callbacks. This will not automatically remove duplicate-settings. It also does not use reflection and so property-name errors will fail on compilation. This method could be expanded to require a "name" and remove duplicates by using a Dictionary backing (as per Akash's answer) or allow the "setter" to return a value (such as success or failure or the old value, or whatnot).
interface Setter {
void Apply();
}
class Setter<T> : Setter {
public T Data;
public Action<T> SetFn;
public void Apply() {
SetFn(Data);
}
}
List<Setter> changeQueue = new List<Setter>();
void SetValue<T>(Action<T> setFn, T data){
changeQueue.Add(new Setter<T> {
Data = data,
SetFn = setFn,
});
}
void ApplyChanges(){
foreach (var s in changeQueue){
s.Apply();
}
}
// .. later on
SetValue(x => System.Console.WriteLine(x), "hello world!");
ApplyChanges();
This method can also be trivially used "outside" the objects being monitored because all the operations are in potential closures.
Happy coding.