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:
// 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){}
}
// MyClass → false
class MyClass{}
// MyNamespace → true
namespace MyNamespace{}
// MyNamespace → false
namespace MyNamespace{}
// MyClass → true
class MyClass{}
// 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.
// 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>();
}
}