I've tried with
public string GetContentProperty(Type type)
{
var contentPropertyAttribute = type.GetTypeInfo().GetCustomAttribute<ContentPropertyAttribute>();
return contentPropertyAttribute?.Name;
}
But it always returns null.
In WPF it works OK.
I have been looking at this for longer than I really should have, and still don't know the complete answer. I sincerely hope someone else comes along and provides a better option.
What I've found so far is that on UWP, the call to GetCustomAttributes() returns an empty enumeration. At first I thought this might have something to do with the type-stripping done for UWP assemblies, but I can reproduce the issue in a Debug build, without the "Compile with .NET Native tool chain" option enabled, so the compiled assembly should include complete type information. And even if I modify the Default.rd.xml file to include <Type Name="Windows.UI.Xaml.Markup.ContentPropertyAttribute" Dynamic="Required All"/> (on the theory that maybe the ContentPropertyAttribute type was being omitted), that doesn't help.
So, I'm at a loss as to what exactly is going on. However, in the meantime, here is a version of your method that will work:
static string GetContentProperty<TSource>()
{
return typeof(TSource).GetTypeInfo().CustomAttributes
.Where(a => a.AttributeType == typeof(ContentPropertyAttribute))
.FirstOrDefault()?.NamedArguments.Cast<CustomAttributeNamedArgument?>()
.Where(n => n.Value.MemberName == "Name")
.FirstOrDefault()?.TypedValue.Value.ToString();
}
(Rather than pass the Type object in, I just made it generic and let the method do the work of finding the type.)
In the above, I convert the CustomAttributeNamedArgument value type to a nullable type so I can use the FirstOrDefault(), which I find more convenient than having to materialize the enumeration, inspecting its length, and then retrieving the first element if it's non-empty.
The fact that this works even while the GetCustomAttributes() method does not still makes me think that this is somehow related to something that a compiled UWP assembly does that discards type information. But unfortunately, I don't know enough about that specific area of UWP to say how.
I would be the first to agree that the above is not a terribly great option. Having to get the declaration information for the attribute rather than the attribute itself, then searching for the property name in that data, and finally having to cast the untyped value property from the data back to string so it can be returned, that's all very messy and not ideal.
But it does work. So, there's that. :)
Related
I am trying to get all selected items in a solution and this with native code. With native code I am referring to code which does not use the DTE.
I checked the documentation and tried to find a suitable solution, however I din't come very far. What I found was the IVsUiHierarchy which contains the ExecCommand method which contains the following.
Commands that act on a specific item within the hierarchy. (If ItemID equals VSITEMID_SELECTION, the command is applied to the selected item or items.)
So I suspect the method they are talking about, is the before mentioned ExecCommand one. For one I am not quite sure how I will get to the IVsHierarchy object from a IVsHierarchy or similar, on the other hand I am not really sure on how to use the ExecCommand method properly. Additionally I am not even quite certain, if this is even the 'right way' of approaching this.
Note: I am searching for a solution which does not contain the following code in this answer.
You can use IVsMonitorSelection.GetCurrentSelection, to identify all the selected items in the solution explorer.
The above will return you an IVsMultItemSelect interface which you can use to invoke IVsMultiItemSelect.GetSelectedItems to retrieve an array of VSITEMSELECTION values.
There are a few extensibilty samples, that utilize GetSelectedItems, you can use as a reference.
Sincerely,
Ed Dore
I have the following structure:
struct someData
{
public bool check;
public string text;
}
...
someData sd = new someData(){ check = true, text = "just testing" };
Cache.Insert(cacheInd, sd, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(90));
Then later on the code, I want to retrieve the data from cache, but I get an InvalidCastException:
if (Cache[cacheInd] != null)
{
someData sd = (someData)Cache[cacheInd];//Error here
If I try this:
someData sd = Cache[cacheInd] as someData;
I get:
The as operator must be used with a reference type or nullable type ('ASP._dev_pull_aspx.someData' is a non-nullable value type)
Any ideas on how to solve it?
Here's what I'm doing:
Load page (not cached yet) -> everything is fine
Reload it (cached) -> everything is fine
Change code, not related to it somewhere else in the page -> get the exception
Recycling the cache fixes it (until i change code again)
Note: thanks for MethodMan and Michael Humelsine for explanation of as failure - Why can't I use the as keyword for a struct?, but failure to perform cast is still unclear especially since it works most of the time.
It looks like you get 2 different types with type named the same as result of re-compilation of the page and hence you can't cast one to another despite very similar names/structure.
Why:
in .Net type identity includes full name and assembly identity (name) like "System.Int32 from System.dll v4.0.0.0".
changing an ASPX/CSHTML page produces new assembly with random name but does not trigger recycle of app-domain (especially in debug configuration) till some relatively high threshold of "number of dynamically compiled assemblies" is hit (don't have good link handy, search. I.e. this one talks about diff between ASPX vs. Razor )
You should be able to see complete types if you compare whole Type objects (typeof(someData) vs. Cache[cacheInd].GetType() - one of the properties would be different, i.e. Type.FullName likely candidate.
I'd expect the types to look similar to following (with difference in the name of its assembly):
{ASP._dev_pull_aspx.someData from "ASP._dev_pull_aspx._3333.dll"
{ASP._dev_pull_aspx.someData from "ASP._dev_pull_aspx._7777.dll"
To fix you should move types you care about to compiled assemblies from pages or live with the fact that sometimes types will not match and restart app-domain. Normally rebuilding project or web.config change would trigger app-domain recycle as it is part of recycle triggers along with number of recompilations of individual pages.
Notes:
changing struct someData to class someData would still reproduce the error, but you may see more detailed message instead with as types still will be different
the other common cases of such error are having copy of the same type in several assemblies/namespaces due to code sharing (as in include the same source file into multiple project) and using multiple versions of the same strongly named assembly.
Well, I just tested a struct like yours, stored it in cache and retrieved it with the cast syntax (i.e. (someData)Cache[cacheInd]).
It worked fine with no casting issues and no exceptions. What is the value of the "cacheInd" variable in your example? Can it change between the time it is used to store the item in the cache and the time it retrieves it?
Have you debugged to see what the data type is of the object/struct that IS stored in the cache?
The lack of issues I faced seem to point to something other than an issue with serializing/deserializing a struct.
I am building a simple IDE for C#.
..and I am using FastColoredTextBox control for source code editing, with built-in autocomplete menu (http://www.codeproject.com/Articles/161871/Fast-Colored-TextBox-for-syntax-highlighting)
The problem is, that I want to use NRefactor to do automatic code completion, just like in Visual Studio.
I did some research, I found this: https://github.com/lukebuehler/NRefactory-Completion-Sample
...but I didn't understand the code, so I can't reuse it.
To be exact, what I need?
I need an function, which will take as input list of assemblies (array of strings, which are paths to DLLs), current offset, and editor's text.
And as output, I need an array of objects, which will contain name of the object, and it's type (variable, function, type, ...)
So, how do I do it?
Is it necessary to run this autocompletion code in another thread?
Thank you for answers,
VitekST
PS: Don't hate me, I'm not familiar with NRefactor...
I starts to explore NRefactory in same day you asks this question) So, I can't call myself as NRefactory expert. But I can tell you the way, how I use it.
Theoretical material: http://www.codeproject.com/Articles/408663/Using-NRefactory-for-analyzing-Csharp-code
First of all you can use a Visual Studio solution model from this sample project to make similar classes for your IDE solution format: https://github.com/icsharpcode/NRefactory/tree/master/ICSharpCode.NRefactory.ConsistencyCheck
There are three classes you need: CSharpFile, CSharpProject and Solution. Please look at its source code and you will know, how NRefactory performs syntactic analysis of code files. Note "Compilation" field of CSharpProject and "CreateResolver" method of CSharpFile.
Second you need to perform semantic analysis of code. For this purpose you need to implement
ICSharpCode.NRefactory.CSharp.Resolver.IResolveVisitorNavigator
interface. But in your case you better use existing NRefactory implementation:
ICSharpCode.NRefactory.CSharp.Resolver.FindReferencedEntities
Constructor with two parameters waits two handlers. First being executed then resolved syntax element is reference of type, contained in your solution or in the referenced assembly (like variable declaration). Second being executed when resolved syntax element is reference of some type's member (for example "(new object()).ToString()" as a reference of member "ToString" of "object" instance). First parameter of both handlers is AstNode: unresolved syntax element of code. Second parameter is corresponding resolved semantic element: IType for first handler and IMember for another. So you need to create instance of navigator with handlers, that, for example, saving syntax and corresponding semantic elements in dictionaries.
Your code can looks like this:
var solution = new Solution(slnPath);
IDictionary<AstNode, IType> typesMap = new Dictionary<AstNode, IType>();
IDictionary<AstNode, IMember> membersMap = new Dictionary<AstNode, IMember>();
var navigator = new FindReferencedEntities(typesMap.Add, membersMap.Add);
foreach (var codeFile in solution.AllFiles)
{
codeFile.CreateResolver().ApplyNavigator(navigator);
}
After execution of this code dictionaries typesMap and membersMap will containing syntax elements of code, that NRefactory able to resolve, in the keys of dictionaries, and corresponding resolved semantic in values. If you writing autocompletion, in moment of usage processed code can not be compiled with a high probability (because user write it at this moment). So, your app must use not only resolved code, but unresolved too. To get the unresolved syntax elements of code file, than user edit at this moment, you must use:
var syntaxTree = solution.Projects
.Where(p => p.Title.Equals(editableProjName))
.Files
.Where(f => f.FileName.Equals(editableFileNamePath))
.SyntaxTree;
SyntaxTree is a "ICSharpCode.NRefactory.CSharp.SyntaxTree", that inherits AstNode class. It is a root syntax node of the code file. Variable syntaxTree will contain all unresolved syntax elements of current file being edited. To move through the syntax tree you can use AstNode enumerable members like Descendants, Children, GetParent() etc. Or you can use "Visitor" pattern and AstNode method "AcceptVisitor".
While generating list for autocompletion you can use typesMap and membersMap as fast storage of declared types and its members, and syntaxTree as slow storage, if user input stay not found.
NRefactory is a very broad topic, I can't reveal it fully. And it is very sad that this powerful framework haven't got detailed documentations. But I hope my answer can help you.
Resharper wanted me to change this code:
foreach (var item in cmbxColor1.Items)
{
cmbxColor2.Items.Add(item);
. . .
...because it said, "Possible 'System.NullReferencesException'"
So it should be this:
foreach (var item in cmbxColor1.Items)
{
if (null != cmbxColor2.Items)
{
cmbxColor2.Items.Add(item);
. . .
?
I don't get this - how could a combobox's Items be null, unless null == empty? And if null == empty, then that's exactly what they [s,w]ould be when this code is called.
I suppose Resharper is wrong here, as Items collection of the ComboBox seems to be initialized by its constructor. That is:
ComboBox c = new ComboBox();
c.Items.Add("1");
is guaranteed to be OK.
Also only getaccessor is available for us here so that no one could replace this collection with another (or null). Though I am no quite sure, if there were a possibility to influence this collection while deriving from ComboBox (I couldn't find smth at once), I guess even then it still remains guaranteed not null.
Null is not empty.
The Resharper team have done some automatic code analysis of many of the .NET classes to determine which methods and properties can return null. If Resharper claims that it can be null, that's probably because there is some way (perhaps obscure) that it could actually be null.
If you’re using an external library (e.g. mscorlib.dll), it doesn’t seem feasible to specify contracts for its entities using attributes. Enter External Annotations. This ReSharper feature allows you to complement the already compiled entities with attributes used by ReSharper’s analysis engine. External Annotations let you ‘cheat’ the engine, by making it see the attributes (for methods, parameters and other declarations) which weren’t declared at the time the library was compiled. To do this, the attributes must be specified in an XML file located in <ReSharper install directory>\Bin\ExternalAnnotations.
Such is the definition of contracts for standard libraries stored in this folder when ReSharper is installed. These contracts are obtained based on source code analysis as well as Microsoft Contracts. The contracts obtained using the former technique are stored in files of the type *.Generated.xml, while those obtained using the latter technique are stored in files of the type *.Contracts.xml.
However I agree that it's not likely to be null in practice. It could also be that Resharper is over cautious - proving whether something can ever be null or not is a hard problem. You can modify the annotations if you think the analysis is wrong and want to correct it.
Related
ReSharper NullReferenceException Analysis and Its Contracts
i rather use this way.
foreach (var item in cmbxColor1.Items)
{
if (cmbxColor2.Items.Count > 0)
{
cmbxColor2.Items.Add(item);
}
}
Basically what I'm hoping for is something that would work like how the Obsolete attribute works with Intellisense and strikes the method text when typing out the name. What I'm looking for is an attribute that blocks the method from being seen with the assembly it's defined. Kind of like an reverse internal. Using 3.5 by the by.
Yeah sounds odd but if you need the reason why, here it is:
My current solution for lazy loading in entity framework involves having the generated many to one or one to one properties be internal and have a facade? property that is public and basically loads the internal property's value:
public ChatRoom ParentRoom
{
get
{
if(!ParentRoomInnerReference.IsLoaded)
{
ParentRoomInnerReference.Load();
}
return ParentRoomInner;
}
set
{
ParentRoomInner = value;
}
}
Problem with this is if someone tries to use the ParentRoom property in a query:
context.ChatItem.Where(item => item.ParentRoom.Id = someId)
This will blow up since it doesn't know what to do with the facade property when evaluating the expression. This isn't a huge problem since the ParentRoomInner property can be used and queries are only in the entity assembly. (IE no selects and such in the UI assembly) The only situation comes in the entity assembly since it can see both properties and it's possible that someone might forget and use the above query and blow up at runtime.
So it would be nice if there were an attribute or some way to stop the entity assembly from seeing (ie blocked by intellisense) the outward facing properties.
Basically inside the assembly see ParentRoomInner. Outside the assembly see ParentRoom. Going to guess this isn't possible but worth a try.
I do see that there is an attribute
for stopping methods from being
viewable
(System.ComponentModel.EditorBrowsable)
but it's choices are rather slim and
don't really help.
You can use the EditorBrowsableAttribute for this:
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void MyMethod() {}
One thing to know, though: In c#, you will still get intellisense on the method if it is in the same assembly as the one you are working in. Someone referencing your assembly (or your project, for a project reference) will not see it though. You can also pass EditorBrowsableState.Advanced, and then you will only get intellisense if c# if you clear the HideAdvancedMembers option in Tools Options.
I haven't heard of a good way to do this in plain .NET. But, here are some ideas. Maybe one of them will work, or set you off in a direction that will be helpful.
Use FxCop, probably writing your own rule to make sure ParentRoom isn't called from the asslembly that defined it.
Look into the various post-processing projects for .NET (link design-by-contract).
Write some code inside your ParentRoom getter which will check the stack (using "new Stack()" or "new StackFrame(1)" to figure out whether the caller was from the same assembly. If so, either throw an exception or simply return ParentRoomInner.