downcast with string - c#

I have a problem with downcasting, how do I convert the string "Label" to the class type Label for casting and is it possible to reach the 'Texts' class?
public class GFXObject
{
// Constructor etc...
}
public class Label : GFXObject
{
public Texts Text = new TextClass();
// Constructor etc...
}
public class Button : GFXObject
{
// Constructor etc...
}
public class Texts
{
public string Text = "empty";
// Constructor etc...
}
// My List of objects
Dictionary<string, GFXObject> objects;
// Disregarding any troubleshooting
public void ChangeText(string classtype, string name, string text)
{
// How do I convert the string classtype to a ClassType
((classtype)objects[name]).Text.Text = text;
// If parameters would be equal to "Label", "label", "changed":
// ((Label)objects["label"].Text.Text = "changed";
}
Is it possible to use the ChangeText function if extended or modified?

You can do that only via reflection:
public void ChangeText(string classtype, string name, string text)
{
var type = Type.GetType(classtype);
type.GetProperty("Text").SetValue(objects[name], text);
}
Please note that classtype needs to be an assembly-qualified name if the method is in a different assembly than the type. If it is in the same assembly it needs to be fully qualified, i.e. including the namespace.
If that's a problem, you could get rid of the classtype parameter and use this method:
public void ChangeText(string name, string text)
{
var type = objects[name].GetType();
type.GetProperty("Text").SetValue(objects[name], text);
}
Another possibility would be to make use of the DLR and the dynamic keyword:
public void ChangeText(string name, string text)
{
dynamic item = objects[name];
item.Text = text;
}
Please note that every code that uses the dynamic item variable is evaluated only at runtime. This means that this code compiles even if there is no Text property on that particular item. It will then throw an exception at runtime.
Having said all that, the correct solution to this problem would be to introduce a base class or interface that holds the Text property.

Another solution, if the amount of classes being used is small, could be to create a helper to set the property, like:
public void ChangeText(string classtype, string name, string text)
{
switch(classtype)
{
case "ClassType1":
((ClassType1)objects[name]).Text = text;
break;
case "ClassType2":
((ClassType2)objects[name]).Text = text;
break;
etc...
default:
throw new InvalidOperationException("ClassType {0} is not supported", classtype);
}

Related

how to get varriable name over another one c#?

string MyVar1 = "bilah bilah";
dosometing(MyVar1);
void dosometing(object MyObject)
{
string VarName = nameof(MyObject); // it givess : "MyObject"
}
But I was expecting "MyVar1" is there a way for that? using dynamic? or ref?
That's not possible. But you can do something like:
string MyVar1 = "bilah bilah";
dosometing(MyVar1, nameof(MyVar1));
void dosometing(string MyString, string VarName)
{
// MyString holds the value
// VarName holds the variable name
}
Maybe this information is usefull for you.
Since you want the value and the name of the property that has changed you could move the method dosomething inside the setter of the property.
(Notice: I am assuming you are actually working with properties and not local variables as shown in your question, and your question is just simplified)
So something like this:
public class Foo
{
private string _myVar1;
public string MyVar1
{
get => _myVar1;
set
{
_myVar1 = value;
DoSomething(value);
}
}
private void DoSomething(string value, [CallerMemberName]string propertyName = "")
{
Console.WriteLine(value);
Console.WriteLine(propertyName);
}
}
The attribute CallerMemberName requires the using System.Runtime.CompilerServices
More Information can be found here: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callermembernameattribute
See it in action here: https://dotnetfiddle.net/YvqqdP

Reflection : get static property name

I need to get the property name of a static property dynamically called as a parameter.
Here is my Portable Class Library code:
public partial class Test
{
public Test()
{
string staticPropName = Test.GetPropName(Test.Row); // result must be "Row" without additional string
System.Diagnostics.Debug.WriteLine("propName=" + staticPropName);
}
public static int Row { get; set; }
public static string GetPropName(object Property)
{
return "Row"; // using reflection
}
}
I don't know the name of the property and I don't want to define it with an additional string.
You can't do that - when function is called it gets value of the property and have no idea where this value come from. Your sample is equivalent of
string staticPropName = Test.GetPropName(42);
which nobody would expect to return name.
You can try to require Expression as argument so you can actually inspect what method get called with like following staring point (https://stackoverflow.com/questions/1011109/how-do-you-get-the-name-of-the-property):
public static string GetPropName<TResult>(Expression<Func<TResult>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name;
}
string staticPropName = Test.GetPropName(()=> Test.Prop);
Note that you need checks to make sure expression is just one you expect and not something like () => Test + 42 or more complex one and report nice error.

C# Property Reference

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;
}
}

C#: Properties with different return types on derived classes

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.

C# call method on a member class

I want do something like that:
public class MyClass
{
public String varA{ get; set; }
public String[] varB{ get; set; }
//.....
public ?? string ToHtml()
{
//return HTML value
}
}
public class Run()
{
MyClass c = new Myclass();
c.varA = "Toto";
c.varB = new string[] { "foo", "bar" };
string a = c.varA.ToHtml() // -> "<p>Toto</p>";
string b = c.varB.ToHtml() // -> "<ul><li>foo</li><li>bar</li></ul>";
}
How can do that ?
Edit: I have change the Run()
Create an extension method on the String class, which returns a HTML representation of that string (or whatever ToHtml() should do).
public static class StringExtensions
{
public static string ToHtml ( this string target )
{
// TODO :
}
}
This is a way to implement your scenario with extension methods. While, as others have noted, it would make sense to keep the logic to turn your strings to HTML within MyClass, in certain scenarios it might make sense to use this approach.
public class MyClass
{
public String varA{ get; set; }
public String[] varB{ get; set; }
}
public static class MyExtensions {
public static string ToHtml(this string input, string format)
{
return string.Format(format, input);
}
public static string ToHtml(this string input)
{
return ToHtml(input,"<p>{0}</p>");
}
public static string ToHtml(this IEnumerable<string> input, string wrapperformat, string elementformat)
{
string body= input
.Select(s => string.Format(elementformat,s))
.Aggregate((a,b)=> a+b);
return string.Format(wrapperformat,body);
}
public static string ToHtml(this IEnumerable<string> input)
{
return ToHtml(input,"<ul>{0}</ul>","<li>{0}</li>");
}
}
Unless you define ToHtml() extension methods for both strings and arrays, you can't call it that way (on the fields themselves). See the other answers for how to implement extension methods.
A simpler alternative that applies to just MyClass is to make two overloads of your method which accept a string and a string array as arguments respectively, then pass them:
public string ToHtml(string arg)
{
//return HTML value
}
public string ToHtml(string[] argAsArray)
{
//return HTML value
}
Then call them like this:
string a = c.ToHtml(c.varA);
string b = c.ToHtml(c.varB);
What you're trying to do is add an helper method to the string class. It's called an extension method and it must respect certains rules :
It must use this on the first parameter
It must be static
It must be in a static class
.
public static class HtmlStringHelper
{
public static string ToHtml(this string s)
{
// Add you logic here
return (s);
}
}
i suppose you could use an extension method (for both string and string[] for that), but then you would not need the ToHtml() method of MyClass (as the logic would reside in the extension methods).
edit: i should note that calling member methods usually is considered a bad practice. Without more information its hard to imagine what MyClass is supposed to do/be, but you might want to keep control of class members in the class. So another way would be to create a ToHtmlA() and ToHtmlB() method for MyClass.
If you changed ToHtml to except a value:
public static string ToHtml(string a)
{
// your code here - obviously not returning ""
return "";
}
then you can call it like so:
MyClass c = new MyClass();
c.varA = "some text";
c.varA = MyClass.ToHtml(c.varA);
But, I maybe WAY off what you require.

Categories