Cast with GetType() - c#

Is it possible to cast an object to the type returned from GetType()? I'd like a generic method that can accept an object (for anonymous types) but then return an object cast as the anonymous type. I've been thinking of using the LCG DynamicMethod to build a method on a container class, but I can't exactly figure out what that would look like. The idea to cast with the GetType() method was to be able to get the anonymous type and cast an object to its actual type without actually knowing the type.
The overarching goal is to stick anonymous-typed objects into a container, that I could then share and pass between methods.

I can't think of why you'd want to cast as GetType(), because you wouldn't be able to do anything to useful with the result, without knowing the type at compile time anyway.
Perhaps what you are looking for, is being able to Convert. If that is the case, the following should work for you:
object input = GetSomeInput();
object result = Convert.ChangeType(input, someOtherObject.GetType());
We use this when reading values from the registry which are all stored as strings, and then stuffing them into properties using reflection.

Your intent is very unclear; however, one option is generics and MakeGenericMethod in particular. What do you want to do with this? For example:
static class Program
{
static void Main()
{
object obj = 123.45;
typeof(Program).GetMethod("DoSomething")
.MakeGenericMethod(obj.GetType())
.Invoke(null, new object[] { obj });
}
public static void DoSomething<T>(T value)
{
T item = value; // well... now what?
}
}
So now we have the value, typed as double via generics - but there still isn't much we can do with it except for calling other generic methods... what was it you want to do here?

You can use the Activator.CreateInstance method to create an instance from a type.
FYI reflection is SLOOWWWW, so if you need to do this cast many times in a row, it may be better to define your types in an enum or something like this then create instances without using reflection.

I have a class that I use for change tracking in my Windows Forms app because not all items were databound. Most items were TextBox controls, but there were ComboBox and DateTimePicker controls as well.
For simplicity, my HasChanged property tests the generic Windows.Forms.Control to see if it is a ComboBox, but you could test whatever types of controls you add to your Windows Form.
Below is that class - if it helps for anyone.
internal class DataItem
{
private static Color originalBackColor, changedBackColor, originalForeColor, changedForeColor;
private static Font originalFont, changedFont;
static DataItem()
{
originalBackColor = SystemColors.Control;
changedBackColor = SystemColors.HighlightText;
originalForeColor = Color.Black;
changedForeColor = Color.Red;
originalFont = new Font(FontFamily.GenericSansSerif, 12.5f);
changedFont = new Font(originalFont, FontStyle.Bold);
}
public static void ChangeSetup(Control original, Color changedBackgroundColor)
{
originalBackColor = original.BackColor;
originalForeColor = original.ForeColor;
originalFont = original.Font;
changedBackColor = changedBackgroundColor;
changedFont = new Font(originalFont, FontStyle.Bold);
}
private bool changeTracking;
public DataItem(Control control, Object value)
{
this.Control = control;
var current = String.Format("{0}", Control.Text).Trim();
if (Control is ComboBox)
{
var cbo = (ComboBox)Control;
current = cbo.StateGet();
}
this.OriginalValue = current;
this.Control.TextChanged += Control_TextChanged;
changeTracking = true;
}
public Control Control { get; private set; }
private void Control_TextChanged(Object sender, EventArgs e)
{
if (TrackingChanges)
{
if (HasChanged)
{
this.Control.BackColor = originalBackColor;
this.Control.Font = originalFont;
this.Control.ForeColor = originalForeColor;
}
else
{
this.Control.BackColor = changedBackColor;
this.Control.Font = changedFont;
this.Control.ForeColor = changedForeColor;
}
}
}
public bool HasChanged
{
get
{
var current = String.Format("{0}", Control.Text).Trim();
if (Control is ComboBox)
{
var cbo = (ComboBox)Control;
current = cbo.StateGet();
}
return !current.Equals(OriginalValue);
}
}
public String OriginalValue { get; private set; }
public void Reset()
{
changeTracking = false;
this.OriginalValue = String.Empty;
this.Control.Text = String.Empty;
this.Control.BackColor = originalBackColor;
this.Control.Font = originalFont;
this.Control.ForeColor = originalForeColor;
}
public bool TrackingChanges
{
get
{
return changeTracking;
}
}
}

You can use getClass() which returns a Class object then use the cast method in the Class object to cast the object to an object of that Class's type, like so:
myObj.getClass().cast(myObj)

Related

Property edit style as DropDown in a VS .NET custom component

I'd like to use the functionality of a ComboBox as edit option for a var in the properties window of a custom control / component. Not the ComboBox component itself.
As example:
private string[] _stringArray = { "string0", "string1" };
public string[] StringArray
{
get { return _stringArray; }
//callback
//set { _stringArray = value; }
}
As you know this will give me the object browser as view/edit option in the property window.
Funny thing that I can edit the values even with no setter.
In my researches I found out that it is possible ("UITypeEditorEditStyle.DropDown"). But I have no idea how to implement that.
Or what [Instructions] I could set for the "StringArray".
My final goal is a copy of the object selector drop-down of visual studio as a property parameter:
With custom event handling of course. But as you see I'm far away to realize that. :(
I have been looking for a tutorial on the following topics for a long time:
[Designer] instructions reference
A basic tutorial how to manage the display style of properties ✔
However I'm tired of my unsuccessful researches. Some good links are always welcome.
UPDATE:
After I more or less understood the principle (from the link in the comments, thanks) I came to an interim solution.
I realized that I need at least an int var to set a selected `index`. I thought / hoped that VS can do this automatically. Like it does with enums. And my lack of knowledge concerning [Instructions].
I could define a string variable as a placeholder for the selected index of the array in order to do without the TypeConverter, but that would make even less sense. I really don't need another abstract variable for nothing.
So the basis drop-down, which e.g. can display enums directly, does not appear to be applicable. So they use a trick with "UITypeEditorEditStyle.DropDown", which actually isn't a drop-down. It's just a button where you can place the control of your choice. In my case a ListView. Since the "drop" of the "down" already exists. Looks like cheating. ;)
//...
[TypeConverter(typeof(StringArrayConverter))]
public interface IStringArray
{
int SelectedIndex { get; set; }
string[] StringArray { get; set; }
}
public class DropDownStringArray : IStringArray
{
private string[] _stringArray = { "string0", "string1", "string2", "string3", "string4", "string5", "string6" };
public int SelectedIndex { get; set; }
public string[] StringArray
{
get { return _stringArray; }
set { _stringArray = value; }
}
}
private DropDownStringArray _ddsa = new DropDownStringArray();
[Editor(typeof(StringArrayTypeEditor), typeof(UITypeEditor))]
public DropDownStringArray MyDropDownStringArray
{
get { return _ddsa; }
set { _ddsa = value; }
}
//...
public class StringArrayConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
var sa = value as IStringArray;
if (sa != null) { return sa.StringArray[sa.SelectedIndex]; }
}
return "(none)";
}
}
public class StringArrayTypeEditor : UITypeEditor
{
private IWindowsFormsEditorService _editorService;
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; }
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
_editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
DropDownStringArray ddsa = (DropDownStringArray)value;
ListBox lb = new ListBox();
lb.SelectionMode = SelectionMode.One;
for (int i = 0; i < ddsa.StringArray.Length; i++) { lb.Items.Add(ddsa.StringArray[i]); }
lb.SetSelected(ddsa.SelectedIndex, true);
lb.SelectedValueChanged += OnListBoxSelectedValueChanged;
_editorService.DropDownControl(lb);
if (lb.SelectedItem != null) { ddsa.SelectedIndex = lb.SelectedIndex; }
return value;
}
private void OnListBoxSelectedValueChanged(object sender, EventArgs e)
{
_editorService.CloseDropDown();
}
}
Which actually copy the entire class just to change the SelectedIndex. The right thing would be to abuse the SelectedIndex and convert it to a string or something like that. I think I do not care about that anymore. Rather to catch some fresh air. ;)
Maybe that will help someone else.
Note: This is not a practical propose. As example SelectedIndex will not be updated if you change the (length) of the array. I've choosen string[] because it's a really basic and well known type. I am aware that my "program" has no real use. It was just about understanding the principle.

Defining a class member that can be of multiple data types

I have a class member that can take multiple datatypes as shown in the image below..
How do I define such a data member within the class which can take a datatype from one of the mentioned types.Thanks
Declare it as object you can later test it with is:
public object MyProperty { get; set; }
public void DoSomething()
{
if(MyProperty is bool)
{
bool mp = MyProperty as bool;
// do something with boolean type mp
}
else if(MyProperty is string)
{
string mp = MyProperty as string;
// do something wit string type mp
}
// ....
}
In newer version of Visual Studio (I think version 2015 upwards) you can combine the type check and the cast:
public void DoSomething()
{
if(MyProperty is bool mp)
{
// do something with boolean type mp
}
else if(MyProperty is string mp)
{
// do something wit string type mp
}
// ....
}
The benefit of this approach, in comparison to a generic class, would be that the properties type could change during the objects lifetime.
You could use a generic class:
public class MyThing<T>
{
public T MyProperty { get; set; }
}
And now you say what the type is going to be when you create the class:
var myIntObject = new MyThing<int>();
var myStringObject = new MyThing<string>();
myIntObject.MyProperty = 5;
myStringObject.MyProperty = "Hello world";
Object is the common data type,you could manipulate it this way.
private object _classmember;
public object classmember
{
get { return _classmember; }
set
{
_classmember = value;
if (_classmember.GetType()==typeof(Boolean))
{
//Do your stuff
MessageBox.Show("boolean");
}
if (_classmember.GetType() == typeof(int))
{
//Do your stuff
MessageBox.Show("int");
}
if (_classmember.GetType() == typeof(double))
{
//Do your stuff
MessageBox.Show("double");
}
//Declare all the necessary datatypes like the above
}
}
Usage will be like
classmember = true;
classmember = 1;
classmember = 6.6;
In most languages there is the Object datatype which all other datatypes inherit from.

Creating a custom property class for multiple re-use within a class

Suppose I have a C# class that has multiple properties that all look like this:
private bool _var1Dirty = true;
private Double? _var1;
public Double? Var1
{
get
{
if (_var1Dirty)
{
_var1 = Method_Var1();
_var1Dirty = false;
}
return _var1;
}
}
And the only differences between each of these properties would be:
The type of return var (in this case Double?, but could just as easily be int, string, etc)
The method call - Method_Var1() (Each property would have a different one)
Is there any way I could write this as a custom class?
Something along the lines of:
public class Prop
{
public delegate T Func();
private bool _dirty = true;
private T _val;
public T Val
{
get
{
if (_dirty)
{
_val = Func;
_dirty = false;
}
return _val;
}
}
}
And then I could pass into it the:
Return type T
Method Func
(PS - I know this won't compile / is dead wrong, but I wanted to give an idea of what I'm looking for)
Any help / guidance would be really appreciated.
Thanks!!!
You're close. You can do something along the lines of this:
public class Dirty<T>
{
public Dirty(Func<T> valueFactory)
{
this.valueFactory = valueFactory;
dirty = true;
}
private Func<T> valueFactory;
private bool dirty;
private T value;
public T Value
{
get
{
if (dirty)
{
value = valueFactory();
dirty = false;
}
return value;
}
}
}
And you consume it like this:
Dirty<double?> dirtyDouble = new Dirty<double?>(() => SomethingThatReturnsADouble());
double? value = dirtyDouble.Value;
I'm not sure what the dirty checking actually does, but if you need someone more complicated than a bool you can always turn it into some Func<T> the checks for dirtiness.
Edit:
Given #mikez comment and your answer, you can save yourself the creation of the Dirty<T> class by using the built in Lazy<T>, which also guarantess thread safety:
public class F
{
private Lazy<double?> lazyDouble = new Lazy<double?>(() =>
MethodThatReturnsNullableDouble(), true);
public double? Value
{
get
{
return lazyDouble.Value;
}
}
}

Getting attributes for a property where there isn't a direct reference

How do I get attributes of the Stuff property from the DoStuff() method? Is this possible?
public class Bar
{
public enum FooZ
{
Hello,
GoodBye
}
[Display("Hello"]
public FooZ Stuff { get; set; }
public Bar() {
Stuff = FooZ.GoodBye;
}
}
void Main()
{
var x = new Bar();
DoStuff(x.Stuff);
}
void DoStuff(Enum z) {
// How do I get the DisaplyAttribute from here?
}
You can't. The parameter z doesn't remember where it came from; values don't remember how they were constructed. Remember that in this case, the property is what is decorated with the attribute (meaning that it is embedded in the containing-type's metadata), not the value returned by its getter. You have to reflect the Bar type itself, as in Itay's answer.
Type t = typeof(Bar);
PropertyInfo pi = t.GetProperty("Stuff");
Attribute[] att = pi.GetCustomAttributes(typeof(DisplayAttribute), true);

DataGridView List<T> column?

I have a datagridView, that is bound to a List. This List is made up of my class which contains 2 public properties, a String Name, and another List CustomList. See below:
public class MyClass2
{
public string Name
{ get; set;}
public string Description
{
get;
set;
}
}
public class MyClass
{
List<MyClass2> myList;
public string Name
{
get;
set;
}
public List<MyClass2> CustomList
{
get { return myList ?? (myList= new List<MyClass2>()); }
}
}
And then in my designer page:
List<MyClass> myClassList = new List<MyClass>();
dataGridView.DataSource = myClassList;
As it is right now, the only column that appears in the grid, is the MyClass:Name column, and the CustomList column does not show up. What I'd like is the CustomList column to show and to display something like "Collection" with the "..." button showing, and when it is clicked to have the "Collection Editor" to popup.
Does anyone know if this is possible and how to enable it? If there's a tutorial or anything that would help me out I'd appreciate that too. Thanks.
Using generics, I think, is a clean solution:
public class Sorter<T>: IComparer<T>
{
public string Propiedad { get; set; }
public Sorter(string propiedad)
{
this.Propiedad = propiedad;
}
public int Compare(T x, T y)
{
PropertyInfo property = x.GetType().GetProperty(this.Propiedad);
if (property == null)
throw new ApplicationException("El objeto no tiene la propiedad " + this.Propiedad);
return Comparer.DefaultInvariant.Compare(property.GetValue(x, null), property.GetValue(y, null));
}
}
Usage example:
string orderBy = "propertyName";
bool orderAsc = true;
List<MyExampleClass> myClassList = someMethod();
if (!string.IsNullOrEmpty(orderBy))
{
myClassList.Sort(new Sorter<MyExampleClass>(orderBy));
if (!orderAsc) myClassList.Reverse();
}
Short answer: Yes, you can do it with some code.
Long answer: To write the code is gonna be a pain in the ass, as you would have to know not only how the DataGridView behaves with custom columns, but you would need to know how to expose design time elements at runtime, which requires quite a bit of plumbing. Extensive knowledge about the PropertyGrid must also be known.
Note: This might a fun component to write. (I might actually tackle it if I get some time)
So using the 'button' approach posted by Dave, and some code that I found that implements the CollectionEditor, I can edit the CustomList in MyClass2
Here's my solution, although not quite as clean as I'd like:
Put this class somewhere:
class MyHelper : IWindowsFormsEditorService, IServiceProvider, ITypeDescriptorContext
{
public static void EditValue(IWin32Window owner, object component, string propertyName)
{
PropertyDescriptor prop = TypeDescriptor.GetProperties(component)[propertyName];
if (prop == null) throw new ArgumentException("propertyName");
UITypeEditor editor = (UITypeEditor)prop.GetEditor(typeof(UITypeEditor));
MyHelper ctx = new MyHelper(owner, component, prop);
if (editor != null && editor.GetEditStyle(ctx) == UITypeEditorEditStyle.Modal)
{
object value = prop.GetValue(component);
value = editor.EditValue(ctx, ctx, value);
if (!prop.IsReadOnly)
{
prop.SetValue(component, value);
}
}
}
private readonly IWin32Window owner;
private readonly object component;
private readonly PropertyDescriptor property;
private MyHelper(IWin32Window owner, object component, PropertyDescriptor property)
{
this.owner = owner;
this.component = component;
this.property = property;
}
#region IWindowsFormsEditorService Members
public void CloseDropDown()
{
throw new NotImplementedException();
}
public void DropDownControl(System.Windows.Forms.Control control)
{
throw new NotImplementedException();
}
public System.Windows.Forms.DialogResult ShowDialog(System.Windows.Forms.Form dialog)
{
return dialog.ShowDialog(owner);
}
#endregion
#region IServiceProvider Members
public object GetService(Type serviceType)
{
return serviceType == typeof(IWindowsFormsEditorService) ? this : null;
}
#endregion
#region ITypeDescriptorContext Members
IContainer ITypeDescriptorContext.Container
{
get { return null; }
}
object ITypeDescriptorContext.Instance
{
get { return component; }
}
void ITypeDescriptorContext.OnComponentChanged()
{ }
bool ITypeDescriptorContext.OnComponentChanging()
{
return true;
}
PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor
{
get { return property; }
}
#endregion
Add a button column to the data grid:
DataGridViewButtonColumn butt = new DataGridViewButtonColumn();
butt.HeaderText = "CustomList";
butt.Name = "CustomList";
butt.Text = "Edit CustomList...";
butt.UseColumnTextForButtonValue = true;
dataGridView.Columns.Add(butt);
dataGridView.CellClick += new DataGridViewCellEventHandler(dataGridView_CellClick);
Then call it in the button handler of the cell click.
if (e.RowIndex < 0 || e.ColumnIndex != dataGridView.Columns["CustomList"].Index)
return;
//get the name of this column
string name = (string)dataGridView[dataGridView.Columns["Name"].Index, e.RowIndex].Value;
var myClassObject= myClassList.Find(o => o.Name == name);
MyHelper.EditValue(this, myClassObject, "CustomList");
I'd still be interested in hearing other approaches, and not having to implement my own CollectionEditor. And I'm still interested in having it look more like what the TabControl uses to add TabPages in the PropertyGrid...by displaying the "..." button...but this might work for now.
What you want to do is add a column template with a button in it:
http://geekswithblogs.net/carmelhl/archive/2008/11/11/126942.aspx
In the handler for the button, get the selected MyClass item from the collection and bind its list property to a grid in your popup.

Categories

Resources