Create ParseTree (not AST) - c#

I would like to create a parse tree (not an AST) with ANTLR in target language C#. This seems less then trivial, maybe I'm looking in all the wrong places.
So far, I tried to implement the partials in the generated parser as follows:
public partial class TestParser
{
ParseTree pt = new ParseTree("root", null);
partial void EnterRule(string ruleName, int ruleIndex)
{
ParseTree child = new ParseTree(ruleName, pt);
pt.Children.Add(child);
this.pt = child;
}
partial void LeaveRule(string ruleName, int ruleIndex)
{
this.pt = pt.Parent;
}
}
with ParseTree being
public class ParseTree
{
private List<ParseTree> children = new List<ParseTree>();
public ParseTree(string name, ParseTree parent)
{
this.Parent = parent;
this.Rule = name;
}
public ParseTree Parent { get; private set; }
public string Rule { get; private set; }
public List<ParseTree> Children { get { return children; } }
public Boolean IsTerminal
{
get
{
return (children.Count == 0);
}
}
}
This works, but doesn't fulfill my goal: I can't get the matched tokens/text from this tree. Apart from that, it has an additional drawback: If I want to do this for multiple grammars, I have to copy-paste the partial class everywhere, since it's a partial of the TestParser, nothing higher up the foodchain.
I have looked at http://www.antlr.org/wiki/pages/viewpage.action?pageId=1760 but the generated Parser doesn't have a constructor that takes a ParseTreeBuilder.
Where to now?

I've found a more or less reasonable solution to my problem. It has a major drawback: It only handles the text of production rules that consist only of tokens. This is sufficient for me, but might not be for you. A proper implementation should have token nodes too, so it can be properly walked.
Adaptor:
public class ParseAdaptor : CommonTreeAdaptor
{
private C<ParseTree> container;
public ParseAdaptor(C<ParseTree> container)
: base()
{
this.container = container;
}
public override void AddChild(object t, object child)
{
base.AddChild(t, child);
this.container.Value.Text += base.GetTree(child).Text;
}
}
The ParseTree implementation:
public class ParseTree
{
private string ownText;
private List<ParseTree> children = new List<ParseTree>();
public ParseTree(string name, ParseTree parent)
{
this.Parent = parent;
this.Rule = name;
}
public String Text
{
get
{
if (this.IsTerminal) return this.ownText;
else
{
StringBuilder builder = new StringBuilder();
foreach (ParseTree child in children)
{
builder.Append(child.Text);
}
return builder.ToString();
}
}
set
{
this.ownText = value;
}
}
public ParseTree Parent { get; private set; }
public string Rule { get; private set; }
public List<ParseTree> Children { get { return children; } }
public Boolean IsTerminal
{
get
{
return (children.Count == 0);
}
}
}
//Isn't this the silliest little thing you've ever seen?
//Where is a pointer when you need one?
public class C<T>
{
public T Value { get; set; }
}
and it gets glued together with the partials:
public partial class TestParser
{
C<ParseTree> parseTreeContainer = new C<ParseTree>() { Value = new ParseTree("root", null) };
public ParseTree Tree
{
get
{
return parseTreeContainer.Value;
}
set
{
parseTreeContainer.Value = value;
}
}
partial void CreateTreeAdaptor(ref ITreeAdaptor adaptor)
{
adaptor = new ParseAdaptor(this.parseTreeContainer);
}
partial void EnterRule(string ruleName, int ruleIndex)
{
ParseTree child = new ParseTree(ruleName, Tree);
ParseTree parent = Tree;
parent.Children.Add(child);
Tree = child;
}
partial void LeaveRule(string ruleName, int ruleIndex)
{
Tree = Tree.Parent;
}
}

Related

How can I restrict who can make changes using interfaces?

I have a IHasTag interface, a TaggableItem class that implements IHasTag and a TaggingManager class which I want to make it the only one responsible for setting or clearing the Tags but I've been struggling all day trying to implement but with no luck.
How can I make this possible?
public class TaggableItem : TaggingManager.IHasTag
{
public string Tag { get; } // read only
}
public class TaggingManager
{
public interface IHasTag
{
string Tag { get; }
}
private List<IHasTag> _taggedItems = new();
public void TagItem(IHasTag item, string tag)
{
item.Tag = tag; // not working
_taggedItems.Add(item);
}
public void ClearAllTags()
{
foreach (var item in _taggedItems)
{
item.Tag = "": // not working
}
_taggedItems.Clear();
}
}
EDIT
I followed Thomas' suggestion and this is what I end up doing. I know it's not perfect, though. Thank you all for your advices.
public interface ITaggable
{
string? Tag { get; }
}
public interface ISelectable
{
bool IsSelected { get; }
}
public interface IItem : ITaggable, ISelectable
{
}
public class Item : IItem
{
protected Item() { }
public bool IsSelected { get; set; }
public string Tag { get; set; } = string.Empty;
// 'Item' will be created here returning IItem.
// So, unless you 'cast' it, you can't set 'Tag' or 'IsSelected'.
public static IItem CreateItem() => new Item();
}
public class SelectionManager
{
protected List<object> _items = new();
public void Select(ISelectable item)
{
if (item is Item selectable)
{
selectable.IsSelected = true;
_items.Add(item);
}
}
public void Unselect(ISelectable item)
{
if (item is Item selectable)
{
selectable.IsSelected = false;
_items.Remove(item);
}
}
}
public class TaggingManager
{
private List<object> _items = new();
public void Tag(ITaggable item, string tag)
{
if (item is Item taggable)
{
taggable.Tag = tag;
_items.Add(item);
}
}
public void Untag(ITaggable item)
{
if (item is Item taggable)
{
taggable.Tag = string.Empty;
_items.Remove(item);
}
}
}
My suggestion would be to have two interfaces for two purposes: reading and writing.
public interface IHasTag // interface for reading. Maybe IReadTag
{
string Tag { get; }
}
public interface ITagChange // interface for writing. Maybe IWriteTag
{
string Tag { set; }
}
public class TaggableItem : IHasTag, ITagChange // implement both
{
public string Tag { get; set; }
}
// Tagging manager gets write access (ITagChange)
public class TaggingManager
{
private List<ITagChange> _taggedItems = new ();
public void TagItem(ITagChange item, string tag)
{
item.Tag = tag;
_taggedItems.Add(item);
}
public void ClearAllTags()
{
foreach (var item in _taggedItems)
{
item.Tag = "";
}
_taggedItems.Clear();
}
}
// Everyone else has read access only (IHasTag)
class SomeoneElse
{
private List<IHasTag> _taggedItems = new ();
public void DoSomething(IHasTag item)
{
_taggedItems.Add(item);
var tag = item.Tag; // do something with the tag
}
}
class Instantiation
{
public void Main()
{
TaggableItem x = new TaggableItem();
TaggingManager m = new TaggingManager();
m.TagItem(x, "name");
SomeoneElse s = new SomeoneElse();
s.DoSomething(x);
}
}
One possible option is to move the "getter" also to the TagManager. Then the manager is responsible for the tags. The object itself does not even need to know about the tags.
You still can restrict this by exchanging object with an interface.
public class TagManager
{
private Dictionary<object, string> _tagedItems = new Dictionary<object, string>();
public bool HasTag(object item)
{
return _tagedItems.ContainsKey(item);
}
public string GetTag(object item)
{
return _tagedItems[item];
}
public void SetTag(object item, string tag)
{
if(!HasTag(item))
{
_tagedItems.Add(item, tag);
}
else
{
_tagedItems[item] = tag;
}
}
}
I don't think that this is really a answer to the OP, but one possible solution for the underlying problem.

C# generic, where T class : (inheritance class)

I have two type of nodes, one is MyLinkNode it's used as base, another one is GraphNode which inheritance MyLinkNode.
I try to create MyQueue with MyLinkNode. Everything is OK until I try to add GraphNode to MyQueue. I can't use MyQueue with GraphNode since it's bigger.
An alternative way is create another queue for GraphNode, but that means I would need to create lots of class if I have more type of nodes.
Is there any suggestion?
public class MyQueue<T> where T : MyLinkNode<T>
{
private T Head;
private T Last;
public MyQueue(){ ... }
public void Enqueue(T item)
{
item.Prev = Last;
Last.Next = item;
Last = item;
}
}
public class MyGraphQueue
{
//everything is the same with MyQueue besides the Node Type
//I don't want to create like this.
private GraphNode Head;
private GraphNode Last;
public MyGraphQueue(){ ... }
public void Enqueue(GraphNode item)
{
item.Prev = Last;
Last.Next = item;
Last = item;
}
}
public class MyLinkNode<T>
{
public T data { get; set; }
public MyLinkNode<T> Next { get; set; }
public MyLinkNode<T> Prev { get; set; }
}
public class GraphNode<T> : MyLinkNode<T>
{
public GraphNode()
{
this.adjacencyNodes = new List<GraphNode<T>>();
this.isVisited = false;
}
public List<GraphNode<T>> adjacencyNodes;
public bool isVisited { get; set; }
}
public void BFS<T>(GraphNode<T> v)
{
MyQueue<GraphNode<T>> queue = new MyQueue<GraphNode<T>>(); // error, can't implicit convert GraphNode to MyLinkNode<T>
MyGraphQueue queue = new MyGraphQueue(); //It's how I do now.
}
This is a standard Generics inheritance problem. You need to separate what the Queue needs from the generic type. Just add another base class for the queue constraint.
This will keep the queue to have the guarantee of all items having type T and not require extra types or multiple class definitions for all of the concrete types. Eric Lippert has a good article here on why this limitation was required in the generics system.
public class CallingClass
{
public void BFS(GraphNode v)
{
MyQueue<GraphNode> queue = new MyQueue<GraphNode>(); // error, can't implicit convert GraphNode to MyLinkNode<T>
// MyGraphQueue queue = new MyGraphQueue(); //It's how I do now.
}
}
public class QueueItem
{
public QueueItem Next { get; set; }
public QueueItem Prev { get; set; }
}
public class MyQueue<T> where T : QueueItem
{
private T Head;
private T Last;
public MyQueue() { }
public void Enqueue(T item)
{
item.Prev = Last;
Last.Next = item;
Last = item;
}
}
public class MyLinkNode<T>: QueueItem
{
public T data { get; set; }
}
public class GraphNode : MyLinkNode<string>
{
public GraphNode()
{
this.adjacencyNodes = new List<GraphNode>();
this.isVisited = false;
}
public List<GraphNode> adjacencyNodes;
public bool isVisited { get; set; }
}
MyQueue<T> where T : MyLinkNode<T> cannot accept a MyLinkNode<string>
Beacuse here T is string. but, obviously string doesn't inherit from MyLinkNode
I think the solution is simpler than you imagine.
Just set the type (T) of the value in the queue, and inside use MyLinkNode<T>:
public class MyQueue<T>
{
private MyLinkNode<T> Head;
private MyLinkNode<T> Last;
public void Enqueue(MyLinkNode<T> item)
{
item.Prev = Last;
Last.Next = item;
Last = item;
}
}
public void BFS(GraphNode v)
{
MyQueue<string> queue = new MyQueue<string>(); // no error anymore
queue.Enqueue(v);
}
That's not surprising. You need
public class MyQueue<T, S> where T : MyLinkNode<S>
{
private T Head;
private T Last;
public MyQueue() { }
public void Enqueue(T item)
{
item.Prev = Last;
Last.Next = item;
Last = item;
}
}
public void BFS(GraphNode v)
{
MyQueue<GraphNode, string> queue = new MyQueue<GraphNode, string>();
}
The problem is coming from your first line.
Use:
public class MyQueue<T> where T : MyLinkNode<string> { }
Instead of:
public class MyQueue<T> where T : MyLinkNode<T> { }
and it will work fine.

generic abstract class for hierarchical structured

I would like to create an abstract class for hierarchical structured objects.
Here is what I already use, but now I want to make it generic
public class EventBase
{
private EventBase _Parent;
virtual public EventBase Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
}
}
[ForeignKey("Parent")]
private ICustomList<EventBase> _ChildList = new CustomList<EventBase>();
virtual public ICustomList<EventBase> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
}
}
}
something like this:
public class EventBaseGeneric
{
private GenericTypeThatIsSetInTheInheritingClass _Parent;
virtual public GenericTypeThatIsSetInTheInheritingClass Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
}
}
[ForeignKey("Parent")]
private ICustomList<GenericTypeThatIsSetInTheInheritingClass> _ChildList = new CustomList<GenericTypeThatIsSetInTheInheritingClass>();
virtual public ICustomList<GenericTypeThatIsSetInTheInheritingClass> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
}
}
}
Thanks a lot for any idea on how to achiv this !
Best regards,
Fabianus
It would look as follows:
// T generic parameter must inherit EventBase<T>
public class EventBase<T>
where T : EventBase<T>
{
public virtual T Parent { get; set; }
[ForeignKey("Parent")]
public virtual ICustomList<T> ChildList { get; set; } = new CustomList<T>()
}
I found the answer:
public abstract class PersistentObjectBaseWithNameHierarchical <T>
{
private T _Parent;
virtual public T Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
UpdatePropertiesInHierachy();
}
}
[ForeignKey("Parent")]
private ICustomList<T> _ChildList = new CustomList<T>();
virtual public ICustomList<T> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
UpdatePropertiesInHierachy();
}
}
could it be that it has to go like this ?
public abstract class PersistentObjectBaseWithNameHierarchical<T> : PersistentObjectBaseWithName where T : PersistentObjectBaseWithNameHierarchical<T>
{
private PersistentObjectBaseWithNameHierarchical<T> _Parent;
virtual public PersistentObjectBaseWithNameHierarchical<T> Parent
{
get
{
return _Parent;
}
set
{
_Parent = value;
UpdatePropertiesInHierachy();
}
}
[ForeignKey("Parent")]
private ICustomList<PersistentObjectBaseWithNameHierarchical<T>> _ChildList = new CustomList<PersistentObjectBaseWithNameHierarchical<T>>();
virtual public ICustomList<PersistentObjectBaseWithNameHierarchical<T>> ChildList
{
get
{
return _ChildList;
}
set
{
_ChildList = value;
UpdatePropertiesInHierachy();
}
}
public void AddChild(PersistentObjectBaseWithNameHierarchical<T> child)
{
if (ChildList.Count() != 0)
child.OrderPosition = ChildList.Max(e => e.OrderPosition) + 1;
ChildList.Add(child);
}
public void OrderChildList()
{
foreach (var e in ChildList)
{
e.OrderChildList();
}
ChildList.Sort((s1, s2) => s1.OrderPosition.CompareTo(s2.OrderPosition));
}
public int Level
{
get
{
if (Parent != null)
{
return Parent.Level + 1;
}
else
{
return 1;
}
}
}
private double _OrderPosition;
virtual public double OrderPosition
{
get
{
if (_OrderPosition == 0)
{
// We use the Id as OrderPosition to keep creation order by default
_OrderPosition = Id;
}
return _OrderPosition;
}
set
{
_OrderPosition = value;
Parent?.ChildList.Sort((s1, s2) => s1.OrderPosition.CompareTo(s2.OrderPosition));
UpdatePropertiesInHierachy();
}
}
public void UpdatePropertiesInHierachy()
{
PersistentObjectBaseWithNameHierarchical<T> r = GetRoot(this);
DuringUpdatePropertiesInHierachy();
}
Because otherwise I get an error here:
GetRoot(this)
telling
Argument 1: cannot convert from 'HostSystems.Models.PersistentObjectBaseWithNameHierarchical' to 'T'
Thanks for any further advice !
Regards,
Fabianus

How to Create a Class That Can Have Parent and Child Relationship

I have seen quite a few articles on here about my question but none really answer what I am asking. I am creating a class of my Branch objects that you can envision as just like the TreeNode objects of the TreeView control. Each Branch can have any number of Branch children below (and therefore above) it. Here is my rather simple class:
public class Branch {
public string Name { get; set; }
public string Link { get; set; }
public Branch Parent { get; private set; }
public List<Branch> Children { get; set; }
internal Branch(string Name, string Link) {
this.Name = Name;
this.Link = Link;
this.Children = new List<Branch>();
} // Branch - Constructor - Overload
internal Branch(string Name, string Link, List<Branch> Children) {
this.Name = Name;
this.Link = Link;
this.Children = Children;
this.Children.ForEach(delegate(Branch branch) {
branch.Parent = this;
});
} // Branch - Constructor - Overload
public bool HasChildren {
get { return this.Children.Count > 0; }
} // HasChildren - Property - ReadOnly
public string Path {
get {
string Result = "";
Branch parent = this;
while (parent != null) {
Result = string.Format("{0}/{1}", parent.Name, Result);
parent = parent.Parent;
} // while stepping up the tree
return string.IsNullOrWhiteSpace(Result) ? "" : Result.Substring(0, Result.Length - 1);
} // get
} // Path - Property - ReadOnly
This works GREAT if I Add children at the time of instantiation like the following:
List<Branch> Branches = new List<Branch>() {
new Branch("First", "#"),
new Branch("Second", "#"),
new Branch("Third", "#", new List<Branch>() {
new Branch("ThirdSub1", "#"),
new Branch("ThirdSub2", "#")
}),
new Branch("Fourth", "#"),
new Branch("Fifth", "#"),
new Branch("Sixth", "#", new List<Branch>() {
new Branch("SixthSub1", "#"),
new Branch("SixthSub2", "#", new List<Branch>() {
new Branch("SixthSub2Sub1", "#"),
new Branch("SixthSub2Sub2", "#"),
new Branch("SixthSub2Sub3", "#", new List<Branch>() {
new Branch("Deep Deep Deep Undercover", "#"),
}),
}),
}),
new Branch("Seventh", "#"),
new Branch("Eighth", "#"),
};
But if I do the following:
List<Branch> Branches = new List<Branch>();
Branch Test = Branches.Add(new Branch("Something", ""));
Test.Children.Add(new Branch("Child Here", ""));
The "Child Here" node does NOT have a Parent associated with it. Thus it is broken and of course the Path property doesn't work property.
I thought I could override the List's Add method but that is not allowed. What is the best way to handle this? Currently I am not creating my own Collection Class like MyBranches, which I like, but if there is a way of doing what I need while implementing IList or ISet or Collection, then I am willing to do so. But please provide an example.
Thanks!
Just for people in the future looking for this same solution, here is the full class:
public class Branch {
public string Name { get; set; }
public string Link { get; set; }
public Branch Parent { get; set; }
public TreeBranches Children { get; private set; }
internal Branch(string Name, string Link) {
this.Name = Name;
this.Link = Link;
this.Children = new TreeBranches(this);
} // Branch - Constructor - Overload
internal Branch(string Name, string Link, TreeBranches Children) {
this.Name = Name;
this.Link = Link;
this.Children = Children;
this.Children.ToList().ForEach(delegate(Branch branch) {
branch.Parent = this;
});
} // Branch - Constructor - Overload
/// <summary>
/// Returns a boolean indicating if the given Branch has any child Branches.
/// </summary>
public bool HasChildren {
get { return this.Children.Count > 0; }
} // HasChildren - Property - ReadOnly
/// <summary>
/// Gets the path from the oldest ancestor to the current Branch.
/// </summary>
public string Path {
get {
string Result = "";
Branch parent = this;
while (parent != null) {
Result = string.Format("{0}/{1}", parent.Name, Result);
parent = parent.Parent;
} // while stepping up the tree
return string.IsNullOrWhiteSpace(Result) ? "" : Result.Substring(0, Result.Length - 1);
} // get
} // Path - Property - ReadOnly
} // Branch - Class
public class TreeBranches : IList<Branch> {
private List<Branch> branches = new List<Branch>();
private Branch owner;
public TreeBranches() {
this.owner = null;
}
public TreeBranches(Branch owner) {
this.owner = owner;
}
public void Add(Branch branch) {
branch.Parent = this.owner;
this.branches.Add(branch);
}
#region Standard IList Method Implementation
IEnumerator<Branch> IEnumerable<Branch>.GetEnumerator() { return this.branches.GetEnumerator(); }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.branches.GetEnumerator(); }
public int IndexOf(Branch item) { return this.branches.IndexOf(item); }
public void Insert(int index, Branch item) { this.branches.Insert(index, item); }
public void RemoveAt(int index) { this.branches.RemoveAt(index); }
public Branch this[int index] {
get { return this.branches[index]; }
set { this.branches[index] = value; }
}
public void Clear() { this.branches.Clear(); }
public bool Contains(Branch item) { return this.branches.Contains(item); }
public void CopyTo(Branch[] array, int arrayIndex) { this.branches.CopyTo(array, arrayIndex); }
public int Count { get { return this.branches.Count(); } }
public bool IsReadOnly { get { return this.IsReadOnly; } }
public bool Remove(Branch item) { return this.branches.Remove(item); }
#endregion Standard IList Method Implementation
} // TreeBranches - Class
You can derive from Collection<T> instead of List<T>, List<T> is faster, and is optimized for performance, but Collection<T> is more extensible and allows you to override Add() and others.
If performance is not an issue, then use Collection<T>, and if performance is an issue than use Reed's example of containing a List<T> in your own class.

Writing my first DSL in C# and getting hung up on func<T> & Action

I'm taking a crack at writing my first DSL for a simple tool at work. I'm using the builder pattern to setup the complex parent object but am running into brick walls for building out the child collections of the parent object. Here's a sample:
Use:
var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);
Sample with closure (I think that's what they're called):
var myMorningCoffee = Coffee.Make.WithCream().PourIn(
x => {
x.ShotOfExpresso.AtTemperature(100);
x.ShotOfExpresso.AtTemperature(100).OfPremiumType();
}
).WithOuncesToServe(16);
Sample class (without the child PourIn() method as this is what I'm trying to figure out.)
public class Coffee
{
private bool _cream;
public Coffee Make { get new Coffee(); }
public Coffee WithCream()
{
_cream = true;
return this;
}
public Coffee WithOuncesToServe(int ounces)
{
_ounces = ounces;
return this;
}
}
So in my app for work I have the complex object building just fine, but I can't for the life of me figure out how to get the lambda coded for the sub collection on the parent object. (in this example it's the shots (child collection) of expresso).
Perhaps I'm confusing concepts here and I don't mind being set straight; however, I really like how this reads and would like to figure out how to get this working.
Thanks,
Sam
Ok, so I figured out how to write my DSL using an additional expression builder. This is how I wanted my DSL to read:
var myPreferredCoffeeFromStarbucks =
Coffee.Make.WithCream().PourIn(
x =>
{
x.ShotOfExpresso().AtTemperature(100);
x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
}
).ACupSizeInOunces(16);
Here's my passing test:
[TestFixture]
public class CoffeeTests
{
[Test]
public void Can_Create_A_Caramel_Macchiato()
{
var myPreferredCoffeeFromStarbucks =
Coffee.Make.WithCream().PourIn(
x =>
{
x.ShotOfExpresso().AtTemperature(100);
x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
}
).ACupSizeInOunces(16);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Count == 2);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == true);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == false);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.CupSizeInOunces.Equals(16));
}
}
And here's my CoffeeExpressionBuilder DSL class(s):
public class Coffee
{
public List<ExpressoExpressionBuilder> expressoExpressions { get; private set; }
public bool HasCream { get; private set; }
public int CupSizeInOunces { get; private set; }
public static Coffee Make
{
get
{
var coffee = new Coffee
{
expressoExpressions = new List<ExpressoExpressionBuilder>()
};
return coffee;
}
}
public Coffee WithCream()
{
HasCream = true;
return this;
}
public Coffee ACupSizeInOunces(int ounces)
{
CupSizeInOunces = ounces;
return this;
}
public Coffee PourIn(Action<ExpressoExpressionBuilder> action)
{
var expression = new ExpressoExpressionBuilder();
action.Invoke(expression);
expressoExpressions.Add(expression);
return this;
}
}
public class ExpressoExpressionBuilder
{
public readonly Queue<ExpressoExpression> ExpressoShots =
new Queue<ExpressoExpression>();
public ExpressoExpressionBuilder ShotOfExpresso()
{
var shot = new ExpressoExpression();
ExpressoShots.Enqueue(shot);
return this;
}
public ExpressoExpressionBuilder AtTemperature(int temp)
{
var recentlyAddedShot = ExpressoShots.Peek();
recentlyAddedShot.Temperature = temp;
return this;
}
public ExpressoExpressionBuilder OfPremiumType()
{
var recentlyAddedShot = ExpressoShots.Peek();
recentlyAddedShot.IsOfPremiumType = true;
return this;
}
}
public class ExpressoExpression
{
public int Temperature { get; set; }
public bool IsOfPremiumType { get; set; }
public ExpressoExpression()
{
Temperature = 0;
IsOfPremiumType = false;
}
}
Any and all suggestions are welcome.
What if .IncludeApps accepted an array of AppRegistrations
IncludeApps(params IAppRegistration[] apps)
then
public static class App
{
public static IAppRegistration IncludeAppFor(AppType type)
{
return new AppRegistration(type);
}
}
public class AppRegistration
{
private AppType _type;
private bool _cost;
public AppRegistration(AppType type)
{
_type = type;
}
public AppRegistration AtNoCost()
{
_cost = 0;
return this;
}
}
so eventually it would look like this...
.IncludeApps
(
App.IncludeAppFor(AppType.Any),
App.IncludeAppFor(AppType.Any).AtNoCost()
)
Inside your IncludeApps method you would inspect the registrations and create the objects as required.
To go the delegate route maybe something like this would work?
var aPhone = MyPhone.Create;
MyPhone.Create.IncludeApps
(
x =>
{
x.IncludeAppFor(new object());
}
);
class MyPhone
{
public MyPhone IncludeApps(Action<MyPhone> includeCommand)
{
includeCommand.Invoke(this);
return this;
}
}
If you aren't set on the delegate route maybe params would work?
var anotherPhone = MyPhone.Create.IncludeApps(
new IncludeAppClass(AppType.Math),
new IncludeAppClass(AppType.Entertainment).AtNoCost());
class MyPhone
{
internal MyPhone IncludeApps(params IncludeAppClass[] includeThese)
{
if (includeThese == null)
{
return this;
}
foreach (var item in includeThese)
{
this.Apps.Add(Item);
}
return this;
}
}

Categories