Fluent Syntax - generic methods
Hi, I have a structure as follows:
and I want to be able to do :
So the rule is that the method .PlacedIn(canvas) must be either last to be called or must be followed by .At().
And .PlacedIn(stackPanel) can be anywhere and followed by any method.
The second problem I solved quite easily by:
But I'm not sure about the .PlacedIn(canvas). I think it should return some other type than the generic
T where : Control
but then the information about the type is lost and I don't know how to return the proper type (Label, Image, ...) In the .At() method afterwards.
How can I do this?16 Replies
If you definitely want the syntax to be
PlacedIn(canvas).At(0, 0)
You can have the placedin overload accepting a canvas return a separate builder type with an At method that returns the original builder
Otherwise it would be simpler to have the position be optional parameters
I can't think of another way to absolutely restrict the usageOh right I can have the .At() method in the builder 🤦♂️ I was still thinking about the method extensions and just didn't know how to return the generic Type in there.
You basically meant something like this, right?
Yes
Only the extension may need to create an instance of positionable control wrapping the original control in order for At to return it
Thanks, I'll try to implement the details and see if it works.
Exactly
If it doesn't work I still think it makes more sense to just have the x and y be parameters for the specific placed at overload
Simpler overall
You can do a lot with interfaces as well. Have the same underlying type (and so the same instance), but implement a bunch of interfaces with different methods, that return other interface types
On mobile - I can type out an example later
That would also work, maybe better
No need for wrapping that way
Hmm, I dont see how it could be done using interfaces? Also some type of generic parameter at interface?
Give me 15 mins, and I'll be at a computer I can type into
Have I understood this right?
Right, I get it now. Neat solution
Thanks a lot
Sweet. You can take that approach quite far: https://github.com/canton7/Stylet/blob/master/Stylet/StyletIoC/FluentInterface.cs
Of course, someone can still type
new Image().PlacedIn(canvas)
and leave it at that
Fluent interfaces are often used for builders, for partially that reason: you can ensure that you only return an instance once the user has reached a particular point in the graph of allowed methodsBut that up to the implementation of the .PlacedIn(canvas) to do "nothing" if it's not followed by the .At() method
So that we ensure that every Control placed in the canvas has coordinates
So if you do
Image.WithUrl(...)
etc, you can make sure that you only return an Image
instance once the user has called PlacedIn
and WithUrl
, for instance
Yeah, but that's a bit of a footgun. The user said to place in a canvas, so why isn't it appearing in the canvas?Oh, so this is more of a bad design decision then?
I'd be tempted to either 1) specify the coordinates in the
PlacedIn
call -- then they can't be forgotten, or 2) do what most other frameworks do and assume (0, 0) if the coordinates aren't specified
I guess there's nothing in your system which forces the user to actually finish the builder -- they don't need the Image
instance for anything later. So there's no way to force them to get as far as building an Image
instanceThat's right. Well thank you for your time and help. Appreciate it