问题
I made custom interface system which uses basic UI controls like button, label, etc. Some controls have many options, so they use long constructors, and they only differ in one or two parameters. And this is work in progress, so I change optional parameters a lot, and it takes quite some time to apply changes to all constructors.
public Button(string Text, Rectangle Rect, Texture2D Texture, bool moreStuff)
public Button(string Text, Point Position, Texture2D Texture, bool moreStuff)
public Button(string Text, Vector2 Position, Texture2D Texture, bool moreStuff)
I tried using dynamic
keyword instead of Rectangle
, Point
and Vector2
to decrease the number of constructors, and it compiles, works, and seems ok for the moment. But maybe I'm missing something that might break this approach later?
To find out what was passed as dynamic Position
I check for .GetType().Name
, use a switch and throw an exception at default:
if it wasn't a recognized type.
Is it fine to do it like this, or is there a better (more safe or appropriate) way?
Currently it's possible to create a fully customized instance of Button
inline, and I wouldn't like to lose that ability.
回答1:
You don't need to define constructor arguments if you're finding it tedious. You could use an object initializer quite nicely:
SomeButton button = new SomeButton()
{
Text = "",
MoreStuff = false
};
回答2:
This calls for a parameter object. That's a class with a property per parameter. Your Button
constructor would now only take one parameter: That parameter object.
Using dynamic
to reduce the number of overloads is definitely not the correct approach.
回答3:
Using dynamic
is not appropritate in your scenario. Having differenct constructor overloads is not a bad thing (not worth than abusing the dynamic
keyword). Many classes in .NET Framework BCL has several constructor overloads (for example, FileStream class has 15 contstructors) and some methods has several overload for differenct uses (MessageBox.Show for example).
回答4:
Another approach is to type this yourself:
class YourPositioningType {
public int X { get; set; }
public int Y { get; set; }
public static YourPositioningType FromVector(Vector2 vector) {
return new YourPositioningType() { X = vector.X, Y = vector.Y };
}
public static YourPositioningType FromRectangle(Rectangle rect) {
// etc..
}
}
Static methods to convert from each of the above types. Then you would call it as:
Button b = new Button("Blah", YourPositioningType.FromVector(new Vector2() { /* etc */));
Then you just use the above class in a single constructor.
回答5:
If you use object initialisers, then you can set each individual property you require independently. You just have to be careful that the various properties can be initialised independently.
For example:
public class Button
{
public int Width
{
get
{
return Rectangle.Width;
}
set
{
Rectangle.Width = value;
}
}
public int Height
{
get
{
return Rectangle.Height;
}
set
{
Rectangle.Height = value;
}
}
public int X
{
get
{
return Rectangle.Left;
}
set
{
Rectangle.Left = value;
}
}
public int Y
{
get
{
return Rectangle.Top;
}
set
{
Rectangle.Top = value;
}
}
public Rectangle Rectangle
{
get;
set;
}
}
If you had a class like the above, you can do either:
var button = new Button
{
Rectangle = new Rectangle(...)
}
or:
var button = new Button
{
Left = 0,
Top = 0,
Width = 100,
Height = 20
}
Object initializer notation is ideal for initializing object via their properties where you can have multiple combinations of properties needing to be set.
来源:https://stackoverflow.com/questions/14909720/reducing-number-of-very-long-constructor-overloads-with-just-a-few-different-par