I need to transform all of the properties of a certain class using Roslyn.
What is the recommended way to apply more than one transformation to a syntax tree without invalidating references into it?
Here is what I've tried and where I'm stuck:
In the first pass a descendant of CSharpSyntaxWalker is visiting all PropertyDeclarationSyntax nodes, and storing them in a list.
In the second pass a CSharpSyntaxRewriter is transforming the nodes while checking that each visited node equals one in the list before transforming it.
The problem with my attempt is: When I transform a property I add new fields to the class which causes the class to mutate. All the references in the list to the other properties become invalid in the new tree for the class.
It seems to be inefficient to revisit the whole class, and either way I cannot detect the property nodes already handled due to the reference difference.
I would not recommend to reference nodes from a SyntaxTree you want to modify. In your case just using a CSharpSyntaxRewriter in a single pass (without keeping references from a pre-processing pass) would be sufficient, because its VisitPropertyDeclaration method will only be called once per property, so there is no need to keep track of the nodes you've already modified.
The CSharpSyntaxRewriter also visits the nodes bottom-up, so the overrides should always be called with a node from the original tree. Most likely you have modified the node through the call to base.VisitPropertyDeclaration() before comparing its reference to the stored one. So you could still keep and compare references if you really wanted to.
public class PropertyRewriter : CSharpSyntaxRewriter
{
public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
// 'node' should be still from the original syntax tree here
node = (PropertyDeclarationSyntax)base.VisitPropertyDeclaration(node);
// 'node' might be replaced here
return node;
}
}
Instead of keeping references to the nodes you want to modify, you could annotate them. Annotations to a node will survive modifications of the containing SyntraxTree as long as the node itself isn't replaced. You can add them like this:
node = node.WithAdditionalAnnotations(
new SyntaxAnnotation("propertyToChange", "todo"));
To retrieve the annotation again either use node.GetAnnotations("propertyToChange") or use GetAnnotatedNodesOrTokens("propertyToChange") to retrieve all nodes or tokens with an annotation of the given kind ("propertyToChange").
Related
It seems like someXml.CreateElement("abc"); does only one thing: create the element. It does not add it as a child as I expected, nor does it seem to do anything else.
But that doesn't make much sense. Why create an element with an instance method instead of with a static method? That would indicate that it does have some relationship to the instance. But I couldn't find anything and hence my question.
The remarks in Microsoft's Documentation mentions that default attributes are created on the returned object. Namespaces come to mind as they may be automatically applied to the new element based on the XmlDocument's schema/defaults.
It also states that it must be manually added to the desired parent node.
From https://msdn.microsoft.com/en-us/library/fw1ys7w6(v=vs.110).aspx
Note that the instance returned implements the XmlElement interface, so default attributes would be created directly on the returned object.
Although this method creates the new object in the context of the document, it does not automatically add the new object to the document tree. To add the new object, you must explicitly call one of the node insert methods.
I think the reason that the method doesn't automatically add the element as a child like you were expecting is because there would be no way to know where the element should be added. The document could have many children and there is nothing to specify which element the created element should be added to. It can't just add it by default to the root element, because there's a good chance that isn't always going to be the desired location.
As previously mentioned, the perks of having it be an instance method rather than a static method would be to automatically create the default attributes (such as namespace) on the newly created element. That way once it is created it should just need to be added to the proper location in the document.
I'm writing a 2D infinite Terrain Editor with focus on performance. Each time the user paints, he creates Nodes which at the moment are assigned to Dictionaries in "Layer" classes. Since the user can paint over existing nodes while he's on a different Layer, I want to find those nodes and destroy them. With my current setup this would involve looping through all the Layers and getting the necessary nodes one by one from the dictionaries.
Obviously, this is way too expensive if done tens of thousands of times per frame. So now I thought I could create just one Dictionary with all the nodes in lists. However, this turns out to use almost as much performance as the previous setup, because now I have to perform a check for whether a Key already exists when instantiating new Nodes :
before:
public Node(){
dic.Add(key,this);
}
now:
public Node(){
List<Node> nodes;
if(dic.TryGetValue(key,out nodes))
nodes.Add(this);
else{
list = new List<Node>();
dic.Add(key,list);
}
}
As you can see, while the current setup saves some performance when checking for nodes, it completely ruins the effect by inflating the instantiation time by the dictionary lookup time.
So now I'm looking for some way to get the same effect as Dictionary<Key,List<Node>> , but without the cost of looking up the list in the dictionary. Is there perhaps a different type of dictionary that lets one stack an infinite (or if necessary a limited) number of Values per Key?
Alternatively, is it possible to somehow order the values in the dictionary so I could use a normal Dictionary<key, Node> and then look up the first key and loop from there through all the values until I hit some Node which no longer fits the search criteria?
In pseudo code, my instantiation functions would look like this :
public Node(){
dic.Add(key+LayerIndex,this);
}
and my lookup function would look something like this
public LookUpAll(key, out list){
var o = dic[key]; // looking up just one node
list.Add(o);
var keyPosition = o.keyPosition;
while(o.position == keyPosition){ // then looping through all other nodes at that position until one comes that has a different position.
o = dic.NextValue();
list.Add(o);
}
}
Now, this does not work as is on the unsorted dictionary, but since I was hoping that someone here could maybe get some inspiration from it and work out a working solution.
How do I reduce the number of lookups in my scenario, or add multiple values per key without looking up the key first?
Since the user can paint over existing nodes while he's on a different
Layer,
I'm going to assume that this is so that you do not end up persisting data that you don't need. But what if the user doesn't intend on deleting data on that layer? He just wants to "see" how something looks. Then he undoes his change and blammo, you have no data on the change he just did so you can't undo it.
Why not just keep all the nodes unless the user explicitly tries to delete them? The end user can always choose what is frustum culled in his end result.
You could also try using a tree-like structure.
If you only care about the topmost node related to a certain key, and on occasion need to iterate over all nodes you could construct a linked list from your nodes. This allows you to iterate over nodes and retrieve the relevant node by key. However it increases the memory consumption of your nodes. You could minimize this by creating a subclass of Node that holds a Next property while leaving the normal nodes without the possibility of an underlying node. This might slow down iteration though.
public Node Next { get; set; }
public Node()
{
Node next;
if (dic.TryGetValue(key, out next))
this.Next = next;
dic[key] = this;
}
I am trying to create a recursive Tuple in C#. One side is a reference a class, and the other side goes into recursion to a likewise datastructure. The right side can be null, and this is when the recursion ends.
At the moment I am using an alias, but this does not seem to work.
using Relation = System.Tuple<Node, Relation>;
Directly typing this is not possible, as this goes infinite.
System.Tuple<Node, System.Tuple<Node, System.Tuple<Node, ...>>>
1.
Is this possible in C#?
2.
Can I do this with aliases?
Extra info
I am doing this because I need to keep track the parent of each node. A node can have multiple children. I cannot edit the node class.
I only need to go up the hierarchy. i.e. I don't need to know a nodes children. I use this for an algorithm where I calculate alot of nodes, and when I find one, I want to find the path to it from bottom to root.
You can create a Class for this.
class Relation
{
Node Node; // Node is another class
Tuple<Node, Relation> Relation;
}
I want to display a tree structure. Do i really need to give the user/tree a predefined hardcoded root node like "RootUnit" where he can add his children or descendants?
Does this make sense or cause only trouble when adding nodes?
If you have two roots then you have two trees.
A tree should have only one root. But you need not hardcode a root. Just treat the first created tree node as root.
A tree by definition has only one root and every child node has exactly one parent (except the root which has no parent). If these restrictions are not met then your tree is no longer a tree but a graph (oriented or not)
It depends on the context. From a strict mathematical definition, you cannot have multiple root nodes to a tree. However, there some implementations of trees that ignore that and have multiple top level nodes anyway (Such as the TreeView control you tagged this question with). You simply need to ask yourself if your particular program would be better or worse with multiple top level nodes. Given that we know nothing else about your program it's not a decision we can really make for you.
Rather than using the same constructor for every node, supply a default constructor used for the root node and one for everything else. It isn't ugly, and it works.
public Node()
{
// Set properties if you'd like.
// such as having no children yet or whatnot.
}
public Node(Node parent)
{
// Similar to Node()
}
See! Nice and clean.
How can I bind an object to a TreeView (WinForms) node in C#?
I thought of something like ExNode : Windows.Forms.Node that can take an object as member besides the treenode name... however I am not sure that is the right approach.
imho you have several strategies :
stick an object of any type in the Tag property of any Node : downside : you'll have to cast it back to its 'native form' when you retrieve it to use it : if that "native form" is anything but type 'Object.
sub-class TreeNode, and add a public fields, Public Properties, or whatever, for your objects ... or even List ... ... or whatever you need to associate with the Node.
assuming your objects are of the same type, you could create a dictionary of type : Dictionary <TreeNode, myObjectType>, instantiate it, and, as needed, store a TreeNode and its associated Object(s) that way as a Key/Value Pair.
Strategies #1, and #3 have the advantage that you can store an associated object ONLY as needed Strategy #2 : is more suited to the case where you anticipate every TreeNode is going to have an associated object(s).
Of course with stragies #1 and #3, you will need to test at run-time for the presence or absence of an object associated with a particular Node.
Strategy #1's an easy test : if the Tag propety of the Node is Null : you know there's no object : if not null ... and there may be more than one type of object stored in the Tag field ... then you'll have to pull out the Tag object, and make sure it's the right type as in : (the example that follows assumes a public class, "Class1," has been assigned to tag of the first node in the TreeView :
TreeNode thisNode = theTreeView.Nodes[0];
if (((thisNode.Tag != null) && (thisNode.Tag is Class1))) ... handle the object ...
Strategy #3 is a little easier since you can just evaluate if the Dictionary<Node, myObject>.Contains the Node as a Key.
Are you looking for something like the Tag property on TreeNodes? It can hold any object.
http://msdn.microsoft.com/en-us/library/system.windows.forms.treenode.tag.aspx
This MSDN article has some good information, for example:
class myTreeNode : TreeNode
{
public string FilePath;
public myTreeNode(string fp)
{
FilePath = fp;
this.Text = fp.Substring(fp.LastIndexOf("\\"));
}
}
You might look into the TreeListView. It isn't perfect, but it works very well and makes the process of displaying objects in a tree view much easier than any other way I have found.