I am inheriting some System.Windows.Forms-Control (about 10 pieces).
Each of them gets some custom extensions, but most of the extension will be the same for each control.
Actually I have to code the same functionality separate for each of them.
This is a lot of copy+paste and difficult to maintain.
class MyButton : Button
{
//this is only in MyButton
public int ButtonProperty { get; set; }
public object Property1 { get; set; }
public object Property2 { get; set; }
public void MakeInvisible()
{
this.Visible = false;
}
}
class MyLabel : Label
{
//this is only in MyLabel
public bool LabelProperty { get; set; }
//same propertys and methods as in MyButton
public object Property1 { get; set; }//copy+paste
public object Property2 { get; set; }//copy+paste
public void MakeInvisible()//copy+paste
{
this.Visible = false;
}
}
What I am searching for is a way to extend all of the derived classes like you can do with an interface or extension method. But I also want to have properties and access the base class (Control)
This is what I am dreaming about:
class MyButton : Button, MyExtension
{
//this is only in MyButton
public int ButtonProperty { get; set; }
}
class MyLabel : Label, MyExtension
{
//this is only in MyLabel
public bool LabelProperty { get; set; }
}
//Extension for all classes inherited from Control
class MyExtension : Control
{
public object Property1 { get; set; }
public object Property2 { get; set; }
public void MakeInvisible()
{
this.Visible = false;
}
}
idea:
create a new type for common properties
give each control a property of that type
implementation:
// TypeConverter required for PropertyGrid in design mode
// found here: http://stackoverflow.com/a/6107953/1506454
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MyExtension
{
// need reference to control to work with in methods
private Control _c;
public MyExtension(Control c)
{
_c = c;
}
// can be inhereted for different controls, if necessary
public string Property1 { get; set; }
public string Property2 { get; set; }
public void MakeInvisible()
{
_c.Visible = false;
}
}
// common interface of extended controls
public interface IExtended
{
MyExtension Extra { get; }
}
// MyButton implements extended interface
public class MyButton : Button, IExtended
{
public MyButton()
{
// create extended properties for button
Extra = new MyExtension(this);
}
// for designer serialization support
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public MyExtension Extra { get; private set; }
//this is only in MyButton
public int ButtonProperty { get; set; }
}
// common extension methods
public static class MyControlHelper
{
public static void MakeInvisible<TControl>(this TControl control) where TControl : Control, IExtended
{
control.Extra.MakeInvisible();
}
public static void Rename<TControl>(this TControl control) where TControl : Control, IExtended
{
control.Text = control.Extra.Property1;
}
}
C# doesn't support multi inheritance. You should try something like this - MyButton : MyExtension; and MyExtension : Button. In this case you will extend MyButton class with MyExtension and Button classes.
You can use extension methods for this purpose
public static class ControlHelper
{
public static void MakeInvisible(this Control c)
{
c.Visible = false;
}
}
and use it like this
var mb = new MyButton();
mb.MakeInvisible();
var ml = new MyLabel();
ml.MakeInvisible();
By using this approach you can generate extension methods for base classes and use it in derived classes.
Instead of inheriting from the Button and Label you could use composition.
class MyExtension
{
protected Control control;
public MyExtension(Control control)
{
this.control = control;
}
public object Property1 { get; set; }
public object Property2 { get; set; }
public void MakeInvisible()
{
this.control.Visible = false;
}
}
class MyButton : MyExtension
{
public MyButton(Button button):base(button){}
public int ButtonProperty { get; set; }
}
class MyLabel : Label
{
public MyButton(Label label):base(label){}
public bool LabelProperty { get; set; }
}
You could even make MyExtension abstract if you don't want any instances of it created. The main difference here is that you'll have to create a Button or Label to pass in and you might want to expose them as properties of your MyButton and MyLabel so you can get at their properties.
If you need to leverage protected methods and properties of the extended controls then you are out of luck, there is no way to acheive what you want without extensive copy and paste.
If you only need access to public methods and properties, then how about something along the following lines:
public interface IControlExtension
{
Foo MyProperty { get; set; }
Blah MyMethod();
}
public abstract class ControlExtension: IControlExtension
{
private Control owner;
private ControlExtension(Control owner)
{
Debug.Assert(owner != null);
this.owner = owner;
}
public static IControlExtension GetControlExtension(Control c)
{
if (c is Button ||
c is Label)
{
return new SimpleControlExtension(c);
}
if (c is Panel || ...
{
return new ContainerControlExtension(c);
}
}
public abstract Foo MyProperty { get; set; }
public abstract Blah MyMethod();
private class SimpleControlExtension: ControlExtension
{
public override Foo MyProperty { .... }
public override Blah MyMethod { ....
}
private class ContainerControlExtension: ControlExtension
{
public override Foo MyProperty { .... }
public override Blah MyMethod { .... }
}
}
Now, in all your extended controls, the copy and paste code is minimum:
public class MyButton : Button
{
public MyButton()
{
....
var controlExtension = ControlExtension.GetControlExtension(this);
}
public IControlExtension { get { return controlExtension; } }
}
Related
I have an arbitrary amount of classes, classThatInherits, anotherClassThatInherits, etc. that inherit classToBeInherited.
I then have a method, b, that needs to be able to access myValue from the classes that inherit classToBeInherited. How can I achieve this, without casting?
//This class will be inherited by other classes
public class classToBeInherited {
public bool isSomething { get; set; }
}
//This class with inherit 'classToBeInherited'
public class classThatInherits : classToBeInherited {
public int myValue { get; set; } //this needs to be accessable...
}
//...And so will this class
public class anotherClassThatInherits : classToBeInherited {
public int myValue { get; set; }
}
private class normalClass {
private void a() {
classThatInherits cti = new classThatInherits();
b(cti);
anotherClassThatInherits acti = new anotherClassThatInherits();
b(acti);
}
private void b(classToBeInherited c) {
//***
//get myValue from the classes that inherit classToBeInherited
//***
}
}
Move myValue to classToBeInherited:
public class classToBeInherited {
public bool isSomething { get; set; }
public abstract int myValue { get; set; }
}
Then in classThatInherits and anotherClassThatInherits use public override int myValue { get; set; } to implement that property.
Ofcorse, if myValue is needed in only some of the classes, then you can have virtual and not abstract property.
var a = c as anotherClassThatInherits;
if (a != null)
{
var myValue = a.myValue;
}
I don't know why you don't want to do casting, but it's very common to have code like above.
UPDATED
If you really don't want casting, you can use reflection (but you still need to know the type of anotherClassThatInherits)
var getter = typeof(anotherClassThatInherits).GetProperty("myValue").GetGetMethod();
var myValue = getter.Invoke(c, null);
I have the following design goal in a class hierarchy:
There is a BaseClass defining some properties, which would usually be read/write:
public class Media
{
public virtual object Content { get; set; }
public virtual double recordingLength { get; set; }
}
The intention is to have some subclasses where this property now is readonly:
public class CompactDisk : Media
{
public override object Content
{
get { return this.getContent(); }
set {
// THERE SHOULDN'T BE A SETTER
}
}
public override double recordingLength
{
get { return 74; }
set {
// NO SETTER EITHER HERE!
}
}
}
I'm lost here, because I don't know how should I implement my design intent.
One possible approach is using interfaces.
You can split your base concept into two interfaces:
public interface IWritableMedia
{
object Content { set; }
double recordingLength { set; }
}
public interface IReadOnlyMedia
{
object Content { get; }
double recordingLength { get; }
}
And then something like CompactDisk should only implement IReadOnlyMedia:
public class CompactDisk : IReadOnlyMedia
{
public object Content { get { return ......; } }
public double recordingLength { get { return .......; } }
}
If you want to implement a CD-RW (rewritable), you should implement both interfaces:
public class RewritableCompactDisk : IReadOnlyMedia, IWritableMedia
{
public object Content { get; set; }
public double recordingLength { get; set; }
}
This way you can type your variables as IReadOnlyMedia or IWritableMedia:
IReadOnlyMedia media = new CompactDisk();
IWritableMedia media2 = new RewritableCompactDisk();
Now the issue is IWritableMedia doesn't provide getters and you don't want to declare another variable of type IReadOnlyMedia. The solution is designing a third interface called IReadWriteMedia and RewritableCompactDisk should implement it:
public interface IReadWriteMedia : IReadOnlyMedia, IWritableMedia
{
}
public class RewritableCompactDisk : IReadWriteMedia
{
public object Content { get; set; }
public double recordingLength { get; set; }
}
Since IReadWriteMedia implements IReadOnlyMedia and IWritableMedia, now you'll be able to type variables with IReadWriteMedia and access both getters and setters:
IReadWriteMedia media3 = new RewritableCompactDisk();
object content = media3.Content;
media3.Content = "hello world";
You can't, or really shouldn't, have a design where the sub types "hide" functionality of the base type. You can:
In your setters throw a NotSupportedException, or similar. This is how the Stream class behaves when you try to set the length of a stream that cannot be set.
Change your design. I don't see a way to get properties working the way you want (without resorting to "hiding", which IMHO isn't a good solution), but perhaps something like this:
public interface IMedia
{
object Content { get; }
double RecordingLength { get; }
}
public interface IWritableMedia : IMedia
{
void SetContent(object content);
void SetRecordingLength(double length);
}
Your CompactDisk would implement the just the IMedia interface, whereas a HardDrive class may choose to implement the IWritableMedia interface.
I want the following, is it possible in C#
public class BaseClass
{
public string Name {get;set;}
public DateTime Login {get;set;}
}
public class ChildA : BaseClass
{
public string SchoolName{get; set;}
public string ClassName{get; set;}
}
public class childB : BaseClass
{
public string StreetAdrees{get; set;}
}
Now I want that if I create an instance of any child class Name="John" and Login "2013-12-12" or from database already set its irritating to set these attribute for every class
just like that
ChildA obj=new ChildA();
obj.Name and obj.Login already have Data
Specify constructor in base class, then create constructors in child classes which inherit from base classes constuctor like below
public class ChildA : BaseClass
{
public ChildA():base(){}
public string SchoolName{get; set;}
public string ClassName{get; set;}
}
public class BaseClass
{
public BaseClass()
{
//set Data
.....
}
....
}
read more about base keyword
In the example below, children would actually point to the same instance of base
The example uses cache, but it could be anything else (session, application state, etc).
public class BaseClass
{
private string _name;
private DateTime _login;
public string Name
{
get
{
return Instance._name;
}
set
{
_name = value;
}
}
public DateTime Login
{
get
{
return Instance._login;
}
set
{
_login = value;
}
}
public static BaseClass Instance
{
get
{
// check if null, return a new instance if null etc...
return HttpContext.Current.Cache["BaseClassInstance"] as BaseClass;
}
set
{
HttpContext.Current.Cache.Insert("BaseClassInstance", value);
}
}
}
public class ChildA : BaseClass
{
public string SchoolName { get; set; }
public string ClassName { get; set; }
}
public class childB : BaseClass
{
public string StreetAdrees { get; set; }
}
testing it:
BaseClass.Instance = new BaseClass() { Login = DateTime.Now, Name = "Test" };
ChildA ch = new ChildA();
ChildA ch2 = new ChildA();
childB chb = new childB();
Response.Write(ch.Login.Millisecond);
Response.Write("<BR/>");
Response.Write(chb.Login.Millisecond);
Result:
906
906
I need to enable editing properties of arbitrary objects (the type of object is only known at run-time). I created the following class:
public class Camera
{
[TypeConverter(typeof(ExpandableObjectConverter))]
public object Configuration
{
get
{
return configuration;
}
set
{
configuration = value;
}
}
public Class1 a;
[TypeConverter(typeof(ExpandableObjectConverter))]
public Class1 A
{
get
{
return a;
}
set
{
a = value;
}
}
}
After selecting object "Camera", I can see the property of Class1 on PropertyGrid, but I can't see the property of object "Configuration". How can I fix this problem?
My assumption was that your form becomes visible before the Configuration property was assigned. You didn't supply enough code to see if that was the case. In order to test out my concern, I created two configuration objects:
public class Configuration1
{
public string Test { get; set; }
public byte Test1 { get; set; }
public int Test2 { get; set; }
}
and
public class Configuration2
{
public char Test3 { get; set; }
public List<string> Test4 { get; set; }
}
I modified your camera class to look like this:
public class Camera
{
public Camera()
{
Configuration1 = new Configuration1();
Configuration2 = new Configuration2();
}
private object configuration;
[TypeConverter(typeof(ExpandableObjectConverter))]
public object Configuration { get; set; }
[TypeConverter(typeof(ExpandableObjectConverter))]
public Configuration1 Configuration1 { get; set; }
[TypeConverter(typeof(ExpandableObjectConverter))]
public Configuration2 Configuration2 { get; set; }
}
I then created a form with a PropertyGrid and two Button instances. I configured the form interactions like this:
public partial class Form1 : Form
{
private readonly Camera camera = new Camera();
public Form1()
{
InitializeComponent();
propertyGrid1.SelectedObject = camera;
}
private void Button1Click(object sender, System.EventArgs e)
{
camera.Configuration = new Configuration2();
UpdatePropertyGrid();
}
private void Button2Click(object sender, System.EventArgs e)
{
camera.Configuration = new Configuration1();
UpdatePropertyGrid();
}
private void UpdatePropertyGrid()
{
propertyGrid1.Refresh();
propertyGrid1.ExpandAllGridItems();
}
}
The startup view looks like this:
After clicking the first button:
After clicking the second button:
If you remove the refresh, the property grid does not work correctly. The alternative is to supply an interface with INotifyPropertyChanged on your classes and properties.
I've got the following question.
I've got one class "Instellingen" that's a field in 3 other classes
public class Instellingen
{
private int _ID;
}
public class Class1: Button
{
private Instellingen _Instellingen;
}
public class Class2 : Label
{
private Instellingen _Instellingen;
}
public class Class3 : TextBox
{
private Instellingen _Instellingen;
}
If I've got another class, that uses the other classes (but it can be anyone of this 3 classes)
Do i have to use a switch? or is there an easier way?
public class AnotherClass
{
public AnotherClass ()
{
GetInstellingenFromClass(new Class1());
GetInstellingenFromClass(new Class2());
GetInstellingenFromClass(new Class3());
}
private void GetInstellingenFromClass(Control c)
{
switch (c.GetType.ToString())
{
case "Class1":
Class1 klasse = (Class1) c;
//Do something with the _Instellingen of this class
break;
case "Class2":
Class2 klasse2 = (Class2) c;
//Do something with the _Instellingen of this class
break;
case "Class3":
Class3 klasse3 = (Class3)c;
//Do something with the _Instellingen of this class
break;
}
}
}
(does there exists something so i can just do something like c._Instellingen --> without converting it first to the right type, where it doesn't matter what type c is?)
I hope you understand my question.
Thanks
You should make an interface that has an Instellingen property and implement it in the three classes.
For example:
interface IHasInstellingen {
Instellingen Instellingen { get; }
}
public class Class1: Label, IHasInstellingen {
public Instellingen Instellingen { get; private set; }
}
public class Class2: Button, IHasInstellingen {
public Instellingen Instellingen { get; private set; }
}
private void GetInstellingenFromClass(IHasInstellingen c) {
Instellingen ig = c.Instellingen;
//Do things...
}
//Alternatively:
private void GetInstellingenFromClass(Control c) {
IHasInstellingen hi = c as IHasInstellingen;
if (hi == null)
return; //Or throw an ArgumentException
Instellingen ig = hi.Instellingen;
//Do things...
}
No, you don't have to use a switch. Actually the concept Interface is what you are looking for. Something like;
public interface IIntelingenProvider
{
Intelingen Item {get;}
}
public class Class1: Label, IIntelingenProvider
{
private Instellingen _Instellingen;
public Intelingen Item { get { return _Instellingen; } }
}
public class Class2: Label, IIntelingenProvider
{
private Instellingen _Instellingen;
public Intelingen Item { get {return _Instellingen; } }
}
And the type you are going to provie to the GetInstellingenFromClass method would be IIntelingenProvider. Hence you can write it as;
private void GetInstellingenFromClass(IIntelingenProvider c)
{
// regardless of the type, they all have an Item property of type Intelingen
// c.Item
}
I suggest you to read and learn more about Interitance and Polymorphism
Polymorphism. In your case, all classes extend Label, so you could have Label define your Instellingen:
public class Label
{
public Instellingen Instellingen
{
get { return ...; }
}
}
Then AnotherClass can just work with Labels:
private void GetInstellingenFromClass(Label l)
{
var instellingen = l.Instellingen;
// do something with instellingen here
}
Of course, if you don't own the Label class you can always subclass it and use that from your classes. Another option is to define an interface with the property and have AnotherClass depend on that interface.
Instead of having each of your three classes derive from Label, can you create an intermediate base class, like LabelWithInstellingen?
Consider using an interface to expose an Instellingen property in the classes that need them.
class Instellingen
{
public int ID { get; set; };
}
interface IHasInstellingen
{
Instellingen Instellingen { get; set; }
}
class MyLabel: Label, IHasInstellingen
{
public Instellingen Instellingen { get; set; }
}
class MyButton: Button, IHasInstellingen
{
public Instellingen Instellingen { get; set; }
}
class AnotherClass
{
public AnotherClass ()
{
GetInstellingenFromClass(new MyLabel());
GetInstellingenFromClass(new MyButton());
// ...
}
private void GetInstellingenFromClass(IHasInstellingenc)
{
Console.WriteLine( c.Instellingen.ID );
// ... Do something with Instellingen
}
}