Route to Roslyn

A journey with C# that is leading to Roslyn

Symbols and types for dummies

March 27, 2020

Roslyn uses a lot of technical terms from programming language and compiler design. Sometimes it can be hard to understand or guess what a property retrieves or a method executes for regular coders. There is not enough samples in the documentation, not enough discussion in stackoverflow, or not a tool to debug or display semantic model and symbols; so I decided to write about symbols in the simplest form, as code snippets.

I especially recommend looking at ISymbol.Kind, ITypeSymbol.SpecialType, ITypeSymbol.Typekind. They can be very useful for considering all cases/types when developing or testing with Roslyn. Here is a compilation of symbol properties and their representations in the language of C#.

Shortcuts:

ISymbol

INamespaceOrTypeSymbol

ITypeSymbol

INamedTypeSymbol



ISymbol



// MyClass(){} → false
// void MyMethod(){} → true

class MyClass{
	MyClass(){}
	void MyMethod(){}
}

// returns assembly/module of the symbol

// MyClass → MyNamespace
namespace MyNamespace{
	class MyClass{}
}

// MyClass → MyNamespace
namespace MyNamespace{
	class MyClass{}
}

// MyInnerClass → MyClass
class MyClass{
	class MyInnerClass{}
}

// MyClass → Public
public class MyClass{}

// class MyClass{} → Span [0..15)
class MyClass{}

// → false
// almost in all cases unless custom IL code or interop with another language is used

// MyClass → false
class MyClass{ }

// MyClass → true
abstract class MyClass{ }

// MyClass<int> → false
class MyClass<T>{
	void MyMethod(MyClass<int> mc){ }
} 

// MyClass<T> → true
class MyClass<T>{
	void MyMethod(MyClass<T> mc){ }
}

// MyMethod → false
void MyMethod(){ }

// MyMethod → true
[DllImport("mybinary.dll")]
static extern void MyMethod();

// i (2nd one) → false
void MyMethod(out int i){
	MyMethod(out i);
}

// _ → true
void MyMethod(out int i){
	MyMethod(out _);
	i = 0;
}

// MyMethod → false
class MyClass : MyBaseClass{
	public void MyMethod(){ }
}

// MyMethod → true
class MyClass : MyBaseClass{
	public override void MyMethod(){ }
}

// MyClass → false
class MyClass{ }

// MyClass → true
sealed class MyClass{ }

// MyClass → false
class MyClass{ }

// MyClass → true
static class MyClass{ }

// MyMethod → false
class MyClass{
	void MyMethod(){ }
}

// MyMethod → true
class MyClass{
	virtual void MyMethod(){ }
}

// using MyString = System.String → Alias
using MyString = System.String;

// int[] → ArrayType
int[] myArray;

// Assembly
// Regular C# code cannot provide this. Roslyn method CSharpCompilation.GetAssemblyOrModuleSymbol() will return this.

// _ → Discard
void MyMethod(out int i){
	MyMethod(out _);
	i = 0;
}

// dynamic → DynamicType
dynamic myDynamic;

// ErrorType
// Regular C# code cannot provide this. This is recieved if the type could not be determined due to an error when calling Roslyn method SemanticModel.GetTypeInfo().

// myEvent → Event
event Action myEvent;

// myField → Field
class MyClass{
	int myField;
}

// default: → Label
switch (0){
    default: break;
}

// myLocal → Local
void MyMethod(){
	var myLocal;
}

// void myMethod(){} → Method
class MyClass{
	void myMethod(){}
}

// class MyClass{} → NamedType
class MyClass{}

// namespace MyNamespace{} → Namespace
namespace MyNamespace{}

// NetModule
// Regular C# code cannot provide this. Roslyn method CSharpCompilation.GetAssemblyOrModuleSymbol() will return this.

// int myParameter → Parameter
void MyMethod(int myParameter){}

// int* → PointerType
int* i;

// #define MYPREPROCESSING → Preprocessing
#define MYPREPROCESSING

// int MyProperty => 3 → Property
class MyClass{
	int MyProperty => 3;
}

// x → RangeVariable
var list = new List<int>();
var item = from x in list select x;

// T → TypeParameter
void MyMethod<T>(){}

// → C#

// → MySourceFile.cs

// MyClass → MyClass
// MyGenericClass → MyGenericClass`1
class MyClass{}
class MyGenericClass<T>{}

// MyClass → MyClass
// MyGenericClass → MyGenericClass
class MyClass{}
class MyGenericClass<T>{}

// MyClass → MyClass
// MyGenericClass<int> → MyGenericClass<T>
class MyClass{}
class MyGenericClass<T>{
	void MyMethod(MyGenericClass<int> p){}
}


INamespaceOrTypeSymbol



// MyClass → false
class MyClass{}

// MyNamespace → true 
namespace MyNamespace{}

// MyNamespace → false
namespace MyNamespace{}

// MyClass → true
class MyClass{}


ITypeSymbol



// MyBaseClass → IMyBaseClassInterface
// MyClass → IMyBaseClassInterface, IMyClassInterface
interface IMyBaseClassInterface{}
interface IMyClassInterface{}
class MyBaseClass : IMyBaseClassInterface{}
class MyClass : MyBaseClass, IMyClassInterface{}

// MyBaseClass → System.Object
// MyClass → MyBaseClass
class MyBaseClass{}
class MyClass : MyBaseClass{}

// MyBaseClass → IMyBaseClassInterface
// MyClass → IMyClassInterface
interface IMyBaseClassInterface{}
interface IMyClassInterface{}
class MyBaseClass : IMyBaseClassInterface{}
class MyClass : MyBaseClass, IMyClassInterface{}

// var → false
var i = 0;

// var → true
var a = new {0};

// MyStruct → false
struct MyStruct{}

// MyStruct → true
readonly struct MyStruct{}

// MyStruct → false
struct MyStruct{}

// MyClass → true
class MyClass{}

// MyStruct → false
struct MyStruct{}

// MyStruct → true
ref struct MyStruct{}

// var → false
var myValue = 0;

// var → true
var myTuple = new (1,2);

// string → false
string s = "";

// int → true
int i = 0;

// MyClass → false
class MyClass{}

// MyStruct → true
struct MyStruct{}

// MyClass<int> → MyClass<T>
class MyClass<T>{
	void MyMethod(MyClass<int> mc){ }
}

SpecialType enumuration documentation gives all the examples, so skipping this property.

https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.specialtype?view=roslyn-dotnet


// int[] → Array
int[] myArray;

// MyClass → Class
class MyClass{}

// MyDelegate → Delegate
delegate void MyDelegate();

// dynamic → Dynamic
dynamic myDynamic;

// MyEnum → Enum
enum MyEnum {One, Two};
MyEnum me;

// Error
// If type cannot be resolved due to ambiguity or accessibility etc.

// MyInterface → Interface
interface MyInterface{}

// Module
// Not available in C#, specific to Visual Basic

// int* → Pointer
int* myPointer;

// MyStruct → Struct
struct MyStruct{}

// Submission
// Regular C# code cannot provide this. Indicates synthesized type by the compiler.

// T → TypeParameter
class MyClass<T>{}

// Unknown
// Regular C# code cannot provide this. Internal error in Roslyn may cause this.


INamedTypeSymbol



// MyClass → 0
class MyClass{}

// MyGenericClass → 2
class MyGenericClass<T1,T2>{}

// → null
// Regular C# code cannot provide this. Indicates synthesized class by the compiler.

// MyClass → MyClass
class MyClass{}{
	void MyMethod(){
		var mc = new MyClass();
	}
}

// MyGenericClass<int> → MyGenericClass<T>
class MyGenericClass<T>{
    void MyMethod(){
        var mgc = new MyGenericClass<int>();
}}

// MyClass → MyClass(), MyClass(int i)
class MyClass{
	static MyClass(){}
	public MyClass(int i){}
}

// MyClass → null
// MyDelegate → void MyClass.MyDelegate.Invoke()
class MyClass{
	delegate void MyDelegate();
}

// MyClass → null
class MyClass{}

// MyEnum → int
enum MyEnum {1,2,3}

// MyShortEnum → short
enum MyShortEnum : short {1,2,3}

// MyClass → MyClass(int i)
class MyClass{
	static MyClass(){}
	public MyClass(int i){}
}

// MyClass → false
class MyClass{}

// MyComClass → true
[ComImport]
[Guid("73EB4AF8-BE9C-4b49-B3A4-24F4FF657B26")]
class MyComClass{}

// MyClass → false
class MyClass{}

// MyGenericClass → true
class MyGenericClass<T1,T2>{}

// → false
// Regular C# code cannot provide this. Internal classes generated by Roslyn can have this.

// → false
// Regular C# code cannot provide this. Indicates synthesized class by the compiler.

// MyClass → false
class MyClass{}

// MySerializableClass → true
[Serializable]
class MySerializableClass{}

// MyGenericClass<T1,T2> → false
// MyGenericClass<,> → true
class MyGenericClass<T1,T2>{
	void MyMethod(){
		var t = typeof(MyGenericClass<,>);
	}
}

// MyClass → myField, MyProperty, MyMethod
class MyClass{
    int myField;
    int MyProperty => 0;
    void MyMethod(){};
}

// MyClass → false
static class MyClass{}

// MyClass → true
static class MyClass{
	public static int MyExtensionMethod(this String str){
        return 0;
    }
}

// MyClass → MyClass()
class MyClass{
	static MyClass(){}
	public MyClass(int i){}
}

// int → Uninitialized
int i;

// (int, float) → int, float
(int, float) t;

// int → null
int i;

// ValueTuple<int, float> → null
ValueTuple<int, float> vt;

// (int, float) → ValueTuple<int, float>
(int, float) t;

// IMyInterface<T1> → None
// IMyInterface<T2?> → Annotated
interface IMyInterface<T>{}
class MyGenericClass<T1, T2> where T2 : struct {
	IMyInterface<T1> myField;
	IMyInterface<T2?> myFieldNullable;
}

// MyGenericClass<int,float> → int,float
// MyGenericClass<T1,T2> → T1,T2

class MyGenericClass<T1,T2>{
	void MyMethod(){
		var mgc = new MyGenericClass<int,float>();
	}
}

// MyGenericClass<int,float> → T1,T2
// MyGenericClass<T1,T2> → T1,T2

class MyGenericClass<T1,T2>{
	void MyMethod(){
		var mgc = new MyGenericClass<int,float>();
	}
}

Share This Post