I want to make a deep Copy for my Class TreeNode. Here is my code:
public TreeNode(TreeNode node, GUIStyle inPointStyle, GUIStyle outPointStyle, Action<ConnectionPoint> OnClickInPoint, Action<ConnectionPoint> OnClickOutPoint)
{
this.rect = new Rect(node.rect);
this.style = new GUIStyle(node.style);
this.inPoint = new ConnectionPoint(this, ConnectionPointType.In, inPointStyle, OnClickInPoint);
this.outPoint = new ConnectionPoint(this, ConnectionPointType.Out, outPointStyle, OnClickOutPoint);
this.defaultNodeStyle = new GUIStyle(node.defaultNodeStyle);
this.selectedNodeStyle = new GUIStyle(node.selectedNodeStyle);
this.allDecorations = new List<GameObject>(node.allDecorations);
this.objs = new Dictionary<GameObject, IndividualSettings>(node.objs);
this.name = String.Copy(node.name);
this.RemoveClonedObj = new Action(node.RemoveClonedObj);
this.OnChangeView = new Action<TreeNode>(node.OnChangeView);
this.OnRemoveNode = new Action<TreeNode>(node.OnRemoveNode);
this.OnCopyNode = new Action<TreeNode>(node.OnCopyNode);
this.PreviewTree = new Action<TreeNode, bool> (node.PreviewTree);
}
However, the Rider gave me the warning:
It seems the Rider was saying that my "new" is meaningless.
If I follow Rider's instruction, usethis.RemoveClonedObj = node.RemoveClonedObj; what will happen for my copyed TreeNode's Actions aftering removing the orginal TreeNode? Will they be removed as well? If so, why does Rider give me such warning?
In C# 2.0 or above, the following codes are equivalent (DelegateType is a delegate type, as its name suggests):
newDelegate = new DelegateType(oldDelegate);
newDelegate = oldDelegate;
(See MSDN - How to: Declare, Instantiate, and Use a Delegate (C# Programming Guide))
Also, Microsoft specifies (see here) that such operation will always create a new instance of DelegateType, which has the same invocation list as the oldDelegate. They do not refer to the same object (don't be confused by the = assignment):
The binding-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:
If E is a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) from E to D.
If E is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) from E to D.
If E is a value, E must be compatible (Delegate declarations) with D, and the result is a reference to a newly created delegate of type D that refers to the same invocation list as E. If E is not compatible with D, a compile-time error occurs.
So regarding your question
What will happen for my copyed TreeNode's Actions aftering removing the orginal TreeNode? Will they be removed as well?
Nothing will happen to them. They will not be removed.
By the way, since you are trying to make a deep copy of your tree-node, I suspect whether it is the correct way. Though you have created a new instance of your delegate, the class instance associated with it (the instance on which member methods will be invoked) stays the same.
Do not link instance methods to each other. This will lead to memory leaks.
Even after the original node is removed and no longer needed by your code, due to the reference from the copy the original instance will live in the memory and not be garbage collected.
I suspect this is not what you want, Test code for this
class Program
{
static void Main(string[] args)
{
First t = new First();
Second s = new Second();
t.Print = s.TestMethod;
s.test = "change";
s = null;
t.Print("Hell"); // can debug and see that the function call goes through and string test is = "change"
}
}
public class First
{
public string s;
public Action<string> Print;
}
public class Second
{
public string test = "created";
public void TestMethod (string test)
{
var res = "hello" + test + test;
}
}
Either your methods on the node should be part of the Node object, this way you do not have to assign them to new nodes, or they should be in a separate class, preferably static, so that creation of new nodes does not lead to a memory issue.
Related
I'm writing an app which converts keys to use resources from a RESX File. This code was working with local variables before:
public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context)
{
var fieldDeclaration = (FieldDeclarationSyntax)context.Node;
if (false == IsValidFieldDeclaration(context, fieldDeclaration))
{
return;
}
var firstVariable = fieldDeclaration.Declaration.Variables.FirstOrDefault();
var dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(firstVariable);
var variableSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
var firstSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation(), firstSymbol.Name));
}
However when I try to get the dataFlowAnalysis I receive an error:
Additional information: statementOrExpression is not a StatementSyntax or an ExpressionSyntax.
How can Ideally just need to see if anyone has written to this variable outside of the declaration.
DataFlow works by analyzing order of execution within a single method.
It doesn't make sense for class-level fields.
Instead, you should use a simple syntax visitor (or SymbolFinder) to search the entire class for assignments to the field.
You'll probably also want to check whether it's ever passed as a ref parameter.
I have a very weird issue and I am clueless as to what is causing this behaviour.
I will provide the relevant code of two classes, to keep this short.
Class A has a method that gets an xml document and puts that in an XDocument object, it uses a method from class B for this. Then it uses a different but similar method from class B to add some additional xml to the XDocument.
For some reason, when I run the test cases, the second method from Class B is never entered. Instead, it gives back null.
Here is the code:
First call to a method in class B, from class A
// Get view (xml) for current supplier
XDocument navigationView = ProductBUS.GetProductNavigationXDocument(suppID, viewName, selectedProductNavigationView);
Second call to a method in class B, from class A (this is the faulty one)
if (true)
{
navigationView = ProductBUS.AddOptionsToNavigationMenu(navigationView);
}
(The if(true) is placeholder code, will be changed in the future to a boolean value. This value needs to come from the DB, which is empty at this point.)
The methods in class B, 1 and 2 respectively.
public XDocument GetProductNavigationXDocument(Guid supplierID, String viewName, string selectedProductNavigationView)
{
// TODO : implementing full scale DI
INavigationViewFactory factory = new NavigationViewFactory();
INavigationView navigationXml = factory.Create(NavigationViewTypes.Product);
return navigationXml.GetNavigationXDocument(supplierID, viewName, selectedProductNavigationView);
}
And the second one (which is never entered)
public XDocument AddOptionsToNavigationMenu(XDocument menu)
{
menu.Element(XmlNames.NodeNames.MenuItems).Add(
new XElement(XmlNames.NodeNames.MenuItem,
new XAttribute(XmlNames.AttributeNames.ID, "27301D05-EBBB-4F39-AC74-B0E944F26C52"),
new XAttribute(XmlNames.AttributeNames.DefaultName, "Options"),
new XAttribute(XmlNames.AttributeNames.NameTranslationID, "9999"),
new XAttribute(XmlNames.AttributeNames.DisplayMode, "Options"),
new XElement(XmlNames.NodeNames.MenuItem,
new XAttribute(XmlNames.AttributeNames.ID, "27301D05-EBBB-4F39-AC74-B0E944F26C57"),
new XAttribute(XmlNames.AttributeNames.NameTranslationID, "9999"),
new XAttribute(XmlNames.AttributeNames.DefaultName, "Notifications"),
new XElement(XmlNames.NodeNames.Subscriptions,
new XElement(XmlNames.NodeNames.Subscription,
new XAttribute(XmlNames.AttributeNames.ID, "7"),
new XAttribute(XmlNames.AttributeNames.DefaultName, "Subscriptions"))))));
return menu;
}
I put breakpoints before, on and after the method call as well as inside of the method. If I run the application, I can debug right through the method. But when I run some test cases, that cover this bit of code, they method call is never entered. Instead, the code equals navigationView to null. I fixed this by putting the method's code in the first class, but I'd like to know why this is an issue.
EDIT
Here is the code of one of the test cases that causes the faulty behavior when tested.
[TestMethod]
public void GetProductDetailNavigationModel_ProductWith3FieldValuesAnd2Documents_MappedObjectIsNotNull()
{
// Arrange
DDSInterfaceBlock.Current.IsImpersonated = false;
Domain.Supplier supplier = new Domain.Supplier().Init();
Domain.User user = new Domain.User().Init().Create();
Domain.Language language = new Domain.Language().Init();
Domain.Product product = new Domain.Product().Init().LinkSupplier(supplier);
Domain.ProductOverview.ProductDetail productDetail = ArrangeProductDetailData(supplier, user, language, product);
XDocument document = ArrangeXDocument(productDetail);
ProductDetail svc = new ProductDetail();
IProduct bus = MockRepository.GenerateStub<IProduct>();
bus.Stub(t => t.GetProductNavigationXDocument(supplier.Id, null, string.Empty))
.IgnoreArguments()
.Return(document);
bus.Stub(t => t.GetProductDetail(supplier.Id, user.Id, product.Id, language.Id, language.Id))
.IgnoreArguments()
.Return(productDetail);
svc.ProductBUS = bus;
svc.UserBUS = MockRepository.GenerateMock<BUS.Interfaces.IUser>();
svc.UserBUS
.Stub(t => t.CheckIfUserInPRAGroup(Guid.Empty))
.IgnoreArguments()
.Return(false);
// Act
Domain.ProductOverview.ProductDetailNavigationModel result
= svc.GetProductDetailNavigationModel(supplier.Id, user.Id, product.Id, language.Id, language.Id);
// Assert
Assert.IsNotNull(result);
}
Could it be because you have a stub for GetProductNavigationXDocument, but there is not sub for AddOptionsToNavigationMenu
I have a bit of complicated situation. I must create analyzers/ code fix providers for situations such as a parameter is only assigned but never used or local variable are never used.
For the parameter situation, I'm going for the method declaration and looking at the parameter list to get all the analyzer. I'm going through assignment expressions within the method and I filter the parameters that were assigned with an helper method.
Where it gets fuzzy is I have no clue or to know when a local variable/parameter is used or not. I've gone through symbols but they can't tell me that variable used/ not used. I could try to find how many times a variable's name was mentioned inside a method by turning the method declaration syntax context in a string and look for the parameters that were assigned but that's simply such a BAD idea.
I'm really stuck and I would some help for this from anyone who had previous experience with this kind of situation.
For people who might ask, I'm mostly looking for the missing logic for the analyzer. I have no idea how the code fix provider will work. If you have an idea of what I could do, feel free to include it in your answer ! As of now, I was thinking that a local variable that's not used could be deleted from a method and the same could go for an unused parameter. I'm not sure at the moment.
UPDATE
I'm now trying to use the DataFlow API but it's not working for me at the moment. The oldest answer of this thread gave me a starting point but it's actually not working.
I came up with my own way :
private static bool IsLocalVariableBeingUsed(VariableDeclaratorSyntax variableDeclarator, SyntaxNodeAnalysisContext syntaxNode)
{
var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(variableDeclarator.SyntaxTree);
var methodBody = variableDeclarator.AncestorsAndSelf(false).OfType<MethodDeclarationSyntax>().First();
var lastMethodNode = methodBody?.ChildNodes().LastOrDefault();
if (lastMethodNode == null)
return false;
var readWrite = syntaxNode.SemanticModel.AnalyzeDataFlow(variableDeclarator, lastMethodNode);
}
But this also is not working. When using a test with NUnit :
var input = #"
class TestClass {
void TestMethod ()
{
int i;
}
}";
I get the following message when the runtime gets to either readWrite or result(from oldest answer):
System.ArgumentOutRangeException Index was out of range Must be non negative and lesser than the size of the collection"
But before that in my analyzer, when I try to validate my node to make sure it's not null and create the appropriate elements for the data flow API, there's no code break (not sure if that is the appropriate term) but at the moment I cannot progress.
You can see whether or not most variable are used (read/written) via the DataFlowAnalysis APIs. I've written an introduction to this API on my blog.
I believe in your case, you're looking for variables that are never read.
var tree = CSharpSyntaxTree.ParseText(#"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
Building on JoshVarty's answer, to get this to work in a diagnostic, I would register a SyntaxNodeAction for all MethodDeclaration Syntax Kinds and then look inside the body for unused variables:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}
given the following classes:
class SomeBuilder<T>
{
public static object Build(int index)
{
...
}
}
class SomeHelper
{
public object GetBuildObj(object value)
{
var valuetype = value.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
SomeBuilder was a generic type so i need a call to MakeGenericType() to make things right.
when i pass a normal type like 'class person' for the value, everything just works, that`s fine.
but when i pass a anonymous type like: new { id=1 }, the handler was successfully created. but invoke this dynamic handler i got a MethodAccessException with these messages:
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1<System.Int32>>.Build(int)" failed.
any help would be appreciated, thx.
btw, if you are interested in SomeDynamicHelper, plz see:
http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker
edit1:
i did the call in main like this:
static void Main(string[] args)
{
// pass a normal class, this will be fine
var value = new Person { id = 1};
new SomeHelper().GetBuildObj(value);
// pass a anonymous type
var value = new { id = 1};
new SomeHelper().GetBuildObj(value); // oops, got a exception here!
}
edit2:
based on the comment i changed my code:
class SomeHelper
{
public object GetBuildObj(object value)
{
//this time i do not use the value, but create a new inner value:
var valuenew = new { id = 1 };
var valuetype = valuenew.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
well, this time there is no exception, but...unfortunately a new problem occured...may be i should open a new thread for the new problem.
thank you guys, for your attentions.
edit3:
hi, after some digging, i also found some useful information. say, the SomeDynamicHelper.GetMethodInvoker() code as below:
DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
this is the core we used here to dynamic create a method. for our context, we need to declare the anonymous type in same assembly with the SomeHelper and SomeBuilder. but, if we can`t do the declaration, what should we do?
ok, you can call DynamicMethod() with last parameter(the skipVisibility), set to true!
hope this will help others with the same problem :)
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1>.Build(int)"
From this you can see that dynamic method try to run an internal\private method called Build, for that you got MethodAccessException.
(The anonymous type is kept in a new generated class)
Adding InternalVisibleTo not always helping because it's helping only if you can rewrite the anonymous type assembly (manually or with interception) and only if the type and method are internals and not private.
In dynamic method you can bind the method to type\module, and to skip visibility check, but this help to access private members of the specified module, so again if the type you trying to access is in a different assembly and the type\method are private you can't do anything.
Well almost. There is a "secret" attribute that you inject to your assembly, called IgnoreAccessChecksTo and then in addition to bounded module and skip visibility maybe it will work.
You can try using [assembly: InternalsVisibleTo("Anonymously Hosted DynamicMethods Assembly")] in the same project where you define the anonymous type.
I had a similar error with a C# class I tried to inject using IKVM-converted Guice. The fix was simply making the affected class (in this case probably SomeBuilder) public and everything worked fine.
I have a class which has the following constructor
public DelayCompositeDesigner(DelayComposite CompositeObject)
{
InitializeComponent();
compositeObject = CompositeObject;
}
along with a default constructor with no parameters.
Next I'm trying to create an instance, but it only works without parameters:
var designer = Activator.CreateInstance(designerAttribute.Designer);
This works just fine, but if I want to pass parameters it does not:
var designer = Activator.CreateInstance(designerAttribute.Designer, new DelayComposite(4));
This results in an MissingMethodException:
Constructor voor type
Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesigner
was not found
Any ideas here?
The problem is I really need to pass an object during construction.
You see I have a designer which loads all the types that inherit from the CompositeBase. These are then added to a list from which the users can drag them to a designer. Upon doing so an instance of the dragged is added to the designer. Each of these classes have custom properties defined on them:
[CompositeMetaData("Delay","Sets the delay between commands",1)]
[CompositeDesigner(typeof(DelayCompositeDesigner))]
public class DelayComposite : CompositeBase
{
}
When the user selects an item in the designer, it looks at these attributes in order to load up a designer for that type. For example, in the case of the DelayComposite it would load up a user control which has a label and a slider which allow the user to set the "Delay" property of the DelayComposite instance.
So far this works fine if I don't pass any parameters to the constructor. The designer creates an instance of the DelayCompositeDesigner and assigns it to the content property of a WPF ContentPresenter.
But since that designer needs to modify the properties of the selected DelayComposite
in the designer, I have to pass this instance to it. That is why the constructor looks lie this:
public DelayCompositeDesigner(DelayComposite CompositeObject)
{
InitializeComponent();
compositeObject = CompositeObject;
}
Suggestions are welcome
#VolkerK
The result of your code is this:
<---- foo
Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesignerVoid
.ctor()
Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesignerVoid
.ctor(Vialis.LightLink.Controller.Scenarios.Composites.DelayComposite)
param:Vialis.LightLink.Controller.Scenarios.Composites.DelayComposite
foo ---->
Leppie, you were correct, I had for some reason referenced the Composites assembly in my UI application... which is not something I should have done as I was loading it at runtime. The following code works:
object composite = Activator.CreateInstance(item.CompositType,(byte)205);
var designer = Activator.CreateInstance(designerAttribute.Designer, composite);
As you can see the code does not have knowledge of the DelayComposite type.
This solves the current problem, but introduces many new ones for what I want to achieve,
either way thank you and thank you to everyone who has replied here.
As for the following code, suggested by multiple people:
var designer = Activator.CreateInstance(
designerAttribute.Designer,
new object[] { new DelayComposite(4) }
);
The Activator.CreateInstance has a signature that looks like this:
Activator.CreateInstance(Type type, params object[] obj)
So it should accept my code, but I will try the suggested code
UPDATE:
I've tried this as suggested:
var designer = Activator.CreateInstance(designerAttribute.Designer, new object[] { new DelayComposite(4)});
The result is the same.
I would think that your call would need to be:
var designer = Activator.CreateInstance(designerAttribute.Designer, new object[] { new DelayComposite(4) });
Unless, of course, it is that, in which case the answer is not immediately obvious.
I think you are dealing with a Type mismatch.
Likely the assembly is referenced in different places, or they are compiled against different versions.
I suggest you iterate through the ConstructorInfo's and do a paramtype == typeof(DelayComposite) on the appropriate parameter.
Though I hate printf-like debugging ...
public static void foo(Type t, params object[] p)
{
System.Diagnostics.Debug.WriteLine("<---- foo");
foreach(System.Reflection.ConstructorInfo ci in t.GetConstructors())
{
System.Diagnostics.Debug.WriteLine(t.FullName + ci.ToString());
}
foreach (object o in p)
{
System.Diagnostics.Debug.WriteLine("param:" + o.GetType().FullName);
}
System.Diagnostics.Debug.WriteLine("foo ---->");
}
// ...
foo(designerAttribute.Designer, new DelayComposite(4));
var designer = Activator.CreateInstance(designerAttribute.Designer, new DelayComposite(4));
What does that print in the visual studio's output window?
If you want to call this contructor...
public DelayCompositeDesigner(DelayComposite CompositeObject)
...just use this:
var designer = Activator.CreateInstance(typeof(DelayCompositeDesigner), new DelayComposite(4));
or
var designer = Activator.CreateInstance<DelayCompositeDesigner>(new DelayComposite(4));
I had a similar issue, however my problem was due to the visibility of the constructor. This stack overflow helped me:
Instantiating a constructor with parameters in an internal class with reflection
I discovered another way of creating an instance of an object without calling the constructor at all while answering another question on SF.
In the System.Runtime.Serialization namespace there is a function FormatterServices.GetUninitializedObject(type) that will create an object without calling constructor.
If you look at that function in Reflector you will see it is making an external call. I don't know how black magic is actually happening under the hood. But I did prove to myself that the constructor was never called but the object was instantiated.
When I encountered this problem, I was using a method that returned the parameter list to plug in to Activator.CreateInstance and it had a different number of arguments than the constructor of the object I was trying to create.
In my case, this code work good with .NET Framework but does not work in .NET Core 3.1. It throws ExecutionEngineException which is uncatchable. But when I change target to .NET 5, it works perfectly. Hope this help some one.
Type type = assembly.GetType(dllName + ".dll");
Activator.CreateInstance(type ), new Stream[] { stream };
You can use the following overload on CreateInstance:
public static Object CreateInstance(
Type type,
Object[] args
)
And in your case it'd be (I think):
var designer = Activator.CreateInstance(
typeof(DelayCompositeDesigner),
new object[] { new DelayComposite(4) }
);
I found a solution to the problem, I was struggling with the same issue.
Here is my activator:
private void LoadTask(FileInfo dll)
{
Assembly assembly = Assembly.LoadFrom(dll.FullName);
foreach (Type type in assembly.GetTypes())
{
var hasInterface = type.GetInterface("ITask") != null;
if (type.IsClass && hasInterface)
{
var instance = Activator.CreateInstance(type, _proxy, _context);
_tasks.Add(type.Name, (ITask)instance);
}
}
}
And here is my class to activate, note that I had to change the constructor params to objects, the only way I could get it to work.
public class CalculateDowntimeTask : Task<CalculateDowntimeTask>
{
public CalculateDowntimeTask(object proxy, object context) :
base((TaskServiceClient)proxy, (TaskDataDataContext)context) { }
public override void Execute()
{
LogMessage(new TaskMessage() { Message = "Testing" });
BroadcastMessage(new TaskMessage() { Message = "Testing" });
}
}