Get all types with roslyn - c#

I want to use Roslyn to get all types used in a piece of code. I started with the following SyntaxWalker:
public class DependenciesCollector : SyntaxWalker
{
public override void VisitIdentifierName(IdentifierNameSyntax node)
{
if (!(node.Parent is UsingDirectiveSyntax))
{
Console.WriteLine(node.PlainName);
}
base.VisitIdentifierName(node);
}
public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
{
Console.WriteLine(node.Expression + "." + node.Name);
base.VisitMemberAccessExpression(node);
}
}
But instead of showing me only the (part) types used, it also shows the using statements while I (as you can see) tried not to show the using statements. Can you tell me what is wrong with this code?
In short: I want only the types excluding namespaces. Is this even possible? (Things like System.Console are ok, System not)

I think you may be a bit confused. This code is not going to show you types at all. It is going to show you the identifier names used in source, and any of the member access expressions (a.b). Some of these may be type names, but most likely they are just code expressions.
If in a method body your write:
System.Console.WriteLine("x")
Syntactically, the compiler doesn't know that System.Console is a type name yet. It parses the pair as a member access expression, no different than the Console.WriteLine part.
In other syntactic locations, the compiler knows better. For example, in a local declaration:
Syntax.Console x = null;
The compiler knows that Syntax.Console refers to a type, so it is parsed as a qualified name, not a member access expression.
If you really want to know what types are used by the code, you should be using the semantic model to discover what type symbols these dotted names correspond to.

Related

Is it possible to statically verify structure of c# expression tree arguments?

I have a method
public static class PropertyLensMixins
{
public static ILens<Source> PropertyLens<O,Source>
( this O o
, Expression<Func<O, Source>> selector
)
where O: class, INotifyPropertyChanged
where Source: class, Immutable
{
return new PropertyLens<O, Source>(o, selector);
}
}
and the idea is to use it this way
this.PropertyLens(p=>p.MyProp)
however it is an error to create a nested expression even though the compiler will accept it
this.PropertyLens(p=>p.MyProp.NestProp)
now I can catch this at runtime by parsing the expression tree. For example
var names = ReactiveUI.Reflection.ExpressionToPropertyNames(selector).ToList();
if (names.Count > 1)
throw new ArgumentException("Selector may only be depth 1", "selector");
I was wondering however, is there any clever way to detect this at compile time? I doubt it because the compiler is happy with the type signature but I thought I might ask anyway.
I have also tried a Resharper pattern to match it as an error
$id0$.PropertyLens($id1$=>$id1$.$id2$.$id3$)
with all placeholders being identifiers but Resharper can't seem to match it.
There is no way to make the compiler reject such code.
One possible alternative would be to create a custom diagnostic using Roslyn. That way, all such errors will be marked by VS. Though it might be too much work for something like this.

Error in C#: "an expression tree may not contain a base access" - why not?

I was calling a method that accepts Expression<Func<bool>>.
As part of the expression I was passing:
this.Bottom == base.lineView.Top
The compiler gave me an error that
an expression tree may not contain a base access
So I simply changed it to
this.Bottom == this.lineView.Top
because the member was protected anyway and now it works.
But this error really got me: why the heck would this base be a problem? Especially if using this instead will work but syntactically be the same result (same variable gets accessed)?
Looking at the System.Linq.Expressions.Expression documentation, I don't think there's an expression type which represents "base member access". Don't forget that even though in your case it meant the same as just this, in other cases it wouldn't:
class Test
{
void Foo()
{
Expression<Func<string>> baseString = () => base.ToString();
}
public override string ToString()
{
return "overridden value";
}
}
Here that would represent a non-virtual call to Object.ToString() (for this). I can't see how that would be represented in an expression tree, hence the error.
Now that leads on to the obvious question of why there isn't a representation of non-virtual base member invocation in expression trees - I'm afraid I can't answer that part... although I can see that if you could build that expression programmatically, that would allow you to bypass normal polymorphism from the outside instead of only from inside the class itself (which is the normal case). That may be the reason. (Admittedly there are other ways of calling methods non-virtually, but that's a different matter, and I dare say there are situations where expression trees are "trusted" but other code isn't.)
Jon's answer is correct. I want to follow up on Jon's comment:
I can see that if you could build that expression programmatically, that would allow you to bypass normal polymorphism from the outside instead of only from inside the class itself (which is the normal case). That may be the reason
Suppose you have
public abstract class B // Prevent instantiation
{
internal B() {} // Prevent subclassing outside the assembly.
public virtual void Dangerous() { ... }
}
public sealed class D : B
{
public override void Dangerous()
{
if (!Allowed()) throw whatever;
base.Dangerous();
}
There should be no way for partially trusted code with a D in hand to call B.Dangerous on the instance of D without doing the safety check in D.Dangerous.
The CLR verifier therefore restricts you from performing a non-virtual invocation (a base invocation is of course non-virtual) on a virtual method from outside the class hierarchy. In fact, it goes even farther; you can't even perform that from a class nested within D ! (Of course if your program is granted the right to skip verification then you can do whatever you want; you can dereference arbitrary pointers to memory in unverifiable code which is a lot worse than making a static call on a virtual method.)
When we were designing expression trees we didn't want to deal with this messy security problem. The easiest thing to do was to simply make the whole thing illegal.
There were a number of other security problems with expression trees that could not so easily be solved, but those are a topic for another day.

Using enums in generic methods in C#

I just started learning C# today, and I am trying to make a generic method which can operate on different enums. I got some code that I found in another question on paper, but the compiler keeps complaining. I was wondering if someone could give me a hand. Here is what I have so far:
static void ReadMenuInput<T>(out T menuInput)
{
while (true)
{
if (enum<T>.TryParse(Console.ReadLine(), out menuInput) && menuInput < sizeof(T))
{
break;
}
Console.WriteLine("Please enter a valid input.");
}
}
Thank you for your help!
There are a couple of different issues with that particular code snippet, some of them easier to deal with than others. A few of them are simply showing your lack of experience:
enum and Enum are not interchangable; one is a class name and one is a C# keyword. In some cases (say, string and String) the keyword is just an alias for the type, but enum is not a type name, it is used to define type names. To call class methods you need to use Enum.
You are trying to call the generic TryParse<> method with the wrong syntax; it should be Enum.TryParse<T>.
Enumerations and integers are not the same type, and you cannot just compare them. They are, however, convertible to one another via an explicit typecast. Since sizeof returns an int, you need such a typecast (but see below).
The more complex issues with your code sample:
sizeof(enum) doesn't do quite what you expect, I think; it returns the size in bytes of the enum, which is typically going to be 4. You probably want the IsDefined method, which lets you know if a particular integer value is defined in an enumerated type
As the compiler will tell you, you can only use generic types in this context that are non-nullable. The way to define this is with a where T: struct constraint on your generic type. Note that, despite its name, this doesn't force your type to be a structure; it simply forces it to be a value type.
There is no way for you specify a constraint on the generic type that it must be an enumerated type; if you pass some other value type into the method, it will throw an exception at run-time. It's up to you to handle this case properly.
Here's a working (as in -- it compiles -- I haven't actually tested it) version of the code snippet you want. However, I will point out that every one of the problems in your original code would be worked out just by reading and understanding the error messages; this is one of the most important skills you should get good at as a C# developer.
static void ReadMenuInput<T>(out T menuInput) where T : struct
{
while (true)
{
if (Enum.TryParse<T>(Console.ReadLine(), out menuInput)
&& Enum.IsDefined(typeof(T), menuInput))
{
break;
}
Console.WriteLine("Please enter a valid input.");
}
}

Why does retrieving the property name on a anonymous type give the following result?

A junior co-worker of mine managed to write very scary, scary code.
printJob.Type = item[LocalFunctions.GetName(new { printJob.Type })].ToString();
public static string GetName<T>(T item) where T : class
{
try
{
return typeof(T).GetProperties()[0].Name;
}
catch (Exception ex)
{
return null;
}
}
What is you gues what will GetName will output? It will output "Type"!
I just don't get how this is possible. My first thought is that MS will create an anonymous type with property that has the same name as the property from which the value came from (compiler magic?). As this cannot possibly be a supported feature, I advised my junior co-worker to not use things he cannot understand.
But that leaves the question open: How is this possible?
Anonymous types infer property names unless they are specified:
If you do not specify member names in the anonymous type, the compiler
gives the anonymous type members the same name as the property being
used to initialize them.
http://msdn.microsoft.com/en-us/library/bb397696.aspx
The compiler then infers the type for the generic at compile time - so typeof(T) works. It is fully supported, even if the code is fragile. What happens when someone refactors the name of the property?
I'd also say it's inadvisable to advise people on topics you don't have an answer to yourself - this is the source of many a www.thedailywtf.com article ;-)
Personally I'd still remove this in favour of more robust code, instead of assuming the property name is always going to be the same.
That's what the compiler (not MS) does when creating anonymous types. It uses The type, name and order of the supplied parameters to construct a new type. This is fully supported and intended to be that way, so there's no reason not to use it.
The compiler has all the information available to do this. It sees what name and type the properties you used to initialize it have (such as printJob.Type) and can use that information to generate the anonymous type for you.
See here for more information:
http://msdn.microsoft.com/en-us/library/bb397696.aspx

c#: Why isn't this ambiguous enum reference resolved using the method signature?

Consider the following code:
namespace ConsoleApplication
{
using NamespaceOne;
using NamespaceTwo;
class Program
{
static void Main(string[] args)
{
// Compilation error. MyEnum is an ambiguous reference
MethodNamespace.MethodClass.Frobble(MyEnum.foo);
}
}
}
namespace MethodNamespace
{
public static class MethodClass
{
public static void Frobble(NamespaceOne.MyEnum val)
{
System.Console.WriteLine("Frobbled a " + val.ToString());
}
}
}
namespace NamespaceOne
{
public enum MyEnum
{
foo, bar, bat, baz
}
}
namespace NamespaceTwo
{
public enum MyEnum
{
foo, bar, bat, baz
}
}
The compiler complains that MyEnum is an ambiguous reference in the call to Frobble(). Since there is no ambiguity in what method is being called, one might expect the compiler to resolve the type reference based on the method signature. Why doesn't it?
Please note that I'm not saying that the compiler should do this. I'm confident that there is a very good reason that it doesn't. I would simply like to know what that reason is.
Paul is correct. In most situation in C# we reason "from inside to outside".
there is no ambiguity in what method is being called,
That it is unambiguous to you is irrelevant to the compiler. The task of overload resolution is to determine whether the method group Frobble can be resolved to a specific method given known arguments. If we can't determine what the argument types are then we don't even try to do overload resolution.
Method groups that just happen to contain only one method are not special in this regard. We still have to have good arguments before overload resolution can succeed.
There are cases where we reason from "outside to inside", namely, when doing type analysis of lambdas. Doing so makes the overload resolution algorithm exceedingly complicated and gives the compiler a problem to solve that is at least NP-HARD in bad cases. But in most scenarios we want to avoid that complexity and expense; expressions are analyzed by analyzing child subexpressions before their parents, not the other way around.
More generally: C# is not a "when the program is ambiguous use heuristics to make guesses about what the programmer probably meant" language. It is a "inform the developer that their program is unclear and possibly broken" language. The portions of the language that are designed to try to resolve ambiguous situations -- like overload resolution or method type inference or implicitly typed arrays -- are carefully designed so that the algorithms have clear rules that take versioning and other real-world aspects into account. Bailing out as soon as one part of the program is ambiguous is one way we achieve this design goal.
If you prefer a more "forgiving" language that tries to figure out what you meant, VB or JScript might be better languages for you. They are more "do what I meant not what I said" languages.
I believe its because the C# compiler won't typically backtrack.
NamespaceOne and NamespaceTwo are defined in the same code file. That would be equivalent to putting them in different code files and referencing them via using statement.
In that case you can see why the names clash. You have equally named enum in two different namesapces and the compiler can't guess which one it is, even though Frobble has a NamespaceOne.MyEnum parameter. Instead of
MethodNamespace.MethodClass.Frobble(MyEnum.foo)
use
MethodNamespace.MethodClass.Frobble(NamespaceOne.MyEnum.foo)

Categories