This is the eighth post in my ongoing series covering the abstractions in Sasa. Previous posts:
- Sasa.Parsing - type-safe, extensible lexing and parsing framework
- Sasa.Dynamics - type-safe polytypic/reflective programming
- Sasa.Func - Type-Safe Delegate Combinators
- Sasa.Option - Handling Optional Values
- Sasa.Result - Handling Exceptional Values
- Sasa.Numbers - Generic Number Extensions
- Sasa.Strings - General String Extensions
Sasa.Types is a static class containing a number of extension methods on System.Type, together with extensions that mirror some of the CLR metadata instructions which aren't typically available in C#. It's available in the core Sasa.dll.
Sasa.Types.Constructor
Sasa.Types.Constructor accepts a lambda expression with a "new" expression designating a type's constructor. It then extracts and returns the ConstructorInfo used that expression:
struct Foo { public Foo(int i) { ... } } ... var x = Types.Constructor(() => new Foo(3)); Console.WriteLine(x); // output: // Void .ctor(Int32)
Sasa.Types.Create
Sasa.Types.Create is a static method used to create a dynamic type in a dynamic assembly, often for code generation purposes. It automates various steps and provides a boolean parameter indicating whether to save the assembly to a file, so you can run verification passes on it:
var newType = Types.Create("TypeFoo", saveAssembly:true, generate: typeBuilder => { // see Microsoft's docs on TypeBuilder: // http://msdn.microsoft.com/en-us/library/system.reflection.emit.typebuilder.aspx ... });
Sasa.Types.Field
Sasa.Types.Field are a set of extension methods used to extract FieldInfo metadata from a simple member access expression for that field:
struct Foo { public int Instance; public static string Static; } ... var instanceField = Types.Field<Foo, int>(x => x.Instance); var staticField = Types.Field<int>(() => Foo.Static); Console.WriteLine(instanceField); Console.WriteLine(staticField); // output: // Int32 Instance // String Static
The first overload is for static field, and the second overload is for instance fields since it accepts an expression taking an instance and returning the field value.
The one caveat is that the C# can't enforce that you properly reference fields, or that you're using the write overload to access static vs. instance fields. Instance fields require an instance in order to reference them, so you must use the overload that accepts two generic arguments. Static fields only require the use of one generic argument.
Sasa.Types.FieldName
Sasa.Types.FieldName is an extension method on FieldInfo that extracts a "normalized" field name. By "normalized", I mean that if the field was a compiler-generated backing field for an auto property, then it will extract the property name. Otherwise, it will just return the field name itself:
public class Foo { public int normalField; public int AutoProperty { get; set; } } var backingField = Types.Property<Foo, int>(x => x.AutoProperty) .GetBackingField(); var normalField = Types.Field<Foo, int>(x => x.normalField); Console.WriteLine(backingField.FieldName()); Console.WriteLine(normalField.FieldName()); // output: // AutoProperty // normalField
Sasa.Types.GetBackingField
Sasa.Types.GetBackingField is an extension method on PropertyInfo that attempts to extract the compiler-generated field metadata:
public class Foo { public int AutoProperty { get; set; } } var backingField = Types.Property<Foo, int>(x => x.AutoProperty) .GetBackingField(); Console.WriteLine(backingField.Name.FieldName()); Console.WriteLine(backingField.Name); // output: // AutoProperty // <AutoProperty>k__BackingField
Note that this method currently depends on the naming convention used by the compiler, so it may not be 100% future-proof. If the convention ever does change, I anticipate updating this implementation to reflect that.
Sasa.Types.GetTypeTree
Sasa.Types.GetTypeTree is an extension method on System.Type that extracts the whole sequence of generic type instances, declarations and arguments that make up a type:
var args = typeof(Pair<int, Pair<string,char>>).GetTypeTree(); // args = new[] // { // typeof(Pair<int, Pair<string, char>>), // typeof(Pair<,>), // typeof(int), // typeof(Pair<string, char>), // typeof(Pair<,>), // typeof(string), typeof(char) // };
Sasa.Types.HasAutoField
Sasa.Types.HasAutoField is an extension method on PropertyInfo that checks whether a property is an auto-property with a compiler-generated backing field:
class Foo { public int Bar { get { return 0; } } public int AutoProp { get; set; } } var autop = Types.Property<Foo, int>(x => x.AutoProp); var normp = Types.Property<Foo, int>(x => x.Bar); Console.WriteLine(autop.HasAutoField()); Console.WriteLine(normp.HasAutoField()); // output: // true // false
Sasa.Types.IsBackingField
Sasa.Types.IsBackingField is an extension method on FieldInfo that checks whether a field is a compiler-generated backing field for a property:
public class Foo { public int normalField; public int AutoProperty { get; set; } } var backingField = Types.Property<Foo, int>(x => x.AutoProperty) .GetBackingField(); var normalField = Types.Field<Foo, int>(x => x.normalField); Console.WriteLine(backingField.IsBackingField()); Console.WriteLine(normalField.IsBackingField()); // output: // true // false
Sasa.Types.IsGenericTypeInstance
Sasa.Types.IsGenericTypeInstance is an extension method on System.Type that checks whether the Type instance is an instantiated generic type definition:
struct Foo { } struct Foo<T> { } Console.WriteLine(typeof(Foo).IsGenericTypeInstance()); Console.WriteLine(typeof(Foo<>).IsGenericTypeInstance()); Console.WriteLine(typeof(Foo<int>).IsGenericTypeInstance()); // output: // false // false // true
Sasa.Types.Method
Sasa.Types.Method is a static method that extracts the MethodInfo of a delegate expression:
struct Foo { public static int DoSomething(string x); public int Otherwise(); } ... var doSomething = Types.Method<Func<string, int>>(() => Foo.DoSomething); var otherwise = Types.Method<Func<Foo, Func<int>>>(x => x.Otherwise); Console.WriteLine(doSomething); Console.WriteLine(otherwise); // output: // Int32 DoSomething(String) // Int32 Otherwise()
The second overload is for instance methods, so it accepts an expression that takes an instance, and returns a delegate to the method of interest.
Sasa.Types.Property
Sasa.Types.Property are a set of extension methods that extract the PropertyInfo of a property access expression:
public class Foo { public static int StaticProperty { get; set; } public int AutoProperty { get; set; } } var sprop = Types.Property(() => Foo.StaticProperty); var iprop = Types.Property<Foo, int>(x => x.AutoProperty); Console.WriteLine(sprop); Console.WriteLine(iprop); // output: // Int32 StaticProperty // Int32 AutoProperty
The first overload is for static properties, and the second overload is for instance properties since it accepts an expression taking an instance and returning the property value.
Sasa.Types.ShortGenericType
Sasa.Types.ShortGenericType is a set of extension methods on System.Type that generates an abbreviated string describing a generic type, ie. assembly references omit versioning and public key information:
var nullableInt = typeof(int?); var nullable = nullableInt.GetGenericTypeDefinition(); Console.WriteLine(nullable.ShortGenericType(nullableInt.GetGenericArguments())); // output: // [System.Nullable`1[[System.Int32, mscorlib]], mscorlib]]
Sasa.Types.ShortName
Sasa.Types.ShortName is a set of extension methods on System.Type that generates an abbreviated string describing any type, including generic types:
Console.WriteLine(typeof(int?).ShortName()); // output: // [System.Nullable`[[System.Int32, mscorlib]], mscorlib]
Sasa.Types.Subtypes
Sasa.Types.Subtypes is a set of extension methods on System.Type that check subtyping relationships on runtime types and type arguments:
Console.WriteLine(typeof(int).Subtypes(typeof(object))); Console.WriteLine(typeof(int).Subtypes<object>()); Console.WriteLine(typeof(int).Subtypes<string>()); // output: // true // true // false
However, this check has an important limitation when dealing with type parameters. See Type.IsAssignableFrom.
Comments