public static TypeReference MakeGeneric(this TypeReference self, params TypeReference[] arguments) { if (self.GenericParameters.Count != arguments.Length) throw new ArgumentException($"generic parameters count of type {self.Name} does not match given number of types"); var instance = new GenericInstanceType(self); foreach (var argument in arguments) instance.GenericArguments.Add(argument); return instance; }
public static GenericInstanceType MakeGenericInstanceType(this TypeReference self, params TypeReference [] arguments) { if (self == null) throw new ArgumentNullException ("self"); if (arguments == null) throw new ArgumentNullException ("arguments"); if (arguments.Length == 0) throw new ArgumentException (); if (self.GenericParameters.Count != arguments.Length) throw new ArgumentException (); var instance = new GenericInstanceType (self); foreach (var argument in arguments) instance.GenericArguments.Add (argument); return instance; }
public static void Accept(this GenericInstanceType genericInstanceType, Unity.Cecil.Visitor.Visitor visitor) { genericInstanceType.DoAccept <GenericInstanceType>(visitor); }
public TypeResolver(GenericInstanceType typeDefinitionContext, GenericInstanceMethod methodDefinitionContext) { m_TypeDefinitionContext = typeDefinitionContext; m_MethodDefinitionContext = methodDefinitionContext; }
public TypeResolver(GenericInstanceType typeDefinitionContext) { m_TypeDefinitionContext = typeDefinitionContext; }
public static bool IsFieldTypeSerializable(TypeReference type, IReadOnlyDictionary <GenericParameter, TypeReference> arguments) { // if it's generic parameter then get its real type if (type.IsGenericParameter) { GenericParameter parameter = (GenericParameter)type; type = arguments[parameter]; } if (type.IsArray) { ArrayType array = (ArrayType)type; // one dimention array only if (!array.IsVector) { return(false); } // if it's generic parameter then get its real type TypeReference elementType = array.ElementType; if (elementType.IsGenericParameter) { GenericParameter parameter = (GenericParameter)elementType; elementType = arguments[parameter]; } // array of arrays isn't serializable if (elementType.IsArray) { return(false); } // array of lists isn't serializable if (MonoType.IsList(elementType)) { return(false); } // check if element is serializable return(IsFieldTypeSerializable(elementType, arguments)); } if (MonoType.IsList(type)) { // list is serialized same way as array, so check its argument GenericInstanceType list = (GenericInstanceType)type; TypeReference listElement = list.GenericArguments[0]; // if it's generic parameter then get its real type if (listElement.IsGenericParameter) { GenericParameter parameter = (GenericParameter)listElement; listElement = arguments[parameter]; } // list of arrays isn't serializable if (listElement.IsArray) { return(false); } // list of lists isn't serializable if (MonoType.IsList(listElement)) { return(false); } // check if element is serializable return(IsFieldTypeSerializable(listElement, arguments)); } if (type.IsPrimitive) { return(true); } if (MonoType.IsString(type)) { return(true); } if (MonoType.IsEngineStruct(type)) { return(true); } if (MonoType.IsEnginePointer(type)) { return(true); } if (type.IsGenericInstance) { return(false); } if (MonoType.IsObject(type)) { return(false); } TypeDefinition definition = type.Resolve(); if (definition.IsInterface) { return(false); } if (MonoType.IsCompilerGenerated(definition)) { return(false); } if (definition.IsSerializable) { return(true); } if (definition.IsEnum) { return(true); } return(false); }
// for [SyncVar] health, weaver generates // // NetworkHealth // { // get => health; // set => GeneratedSyncVarSetter(...) // } // // the setter used to be manually IL generated, but we moved it to C# :) public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId, ref bool WeavingFailed) { //Create the set method MethodDefinition set = new MethodDefinition($"set_Network{originalName}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, weaverTypes.Import(typeof(void))); ILProcessor worker = set.Body.GetILProcessor(); // if (!SyncVarEqual(value, ref playerData)) Instruction endOfMethod = worker.Create(OpCodes.Nop); // NOTE: SyncVar...Equal functions are static. // don't Emit Ldarg_0 aka 'this'. // call WeaverSyncVarSetter<T>(T value, ref T field, ulong dirtyBit, Action<T, T> OnChanged = null) // IL_0000: ldarg.0 // IL_0001: ldarg.1 // IL_0002: ldarg.0 // IL_0003: ldflda int32 Mirror.Examples.Tanks.Tank::health // IL_0008: ldc.i4.1 // IL_0009: conv.i8 // IL_000a: ldnull // IL_000b: call instance void [Mirror]Mirror.NetworkBehaviour::GeneratedSyncVarSetter<int32>(!!0, !!0&, uint64, class [netstandard]System.Action`2<!!0, !!0>) // IL_0010: ret // 'this.' for the call worker.Emit(OpCodes.Ldarg_0); // first push 'value' worker.Emit(OpCodes.Ldarg_1); // push 'ref T this.field' worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, fd); // push the dirty bit for this SyncVar worker.Emit(OpCodes.Ldc_I8, dirtyBit); // hook? MethodDefinition hookMethod = GetHookMethod(td, fd, ref WeavingFailed); if (hookMethod != null) { // IL_000a: ldarg.0 // IL_000b: ldftn instance void Mirror.Examples.Tanks.Tank::ExampleHook(int32, int32) // IL_0011: newobj instance void class [netstandard]System.Action`2<int32, int32>::.ctor(object, native int) // this. worker.Emit(OpCodes.Ldarg_0); // the function worker.Emit(OpCodes.Ldftn, hookMethod); // call 'new Action<T,T>()' constructor to convert the function to an action // we need to make an instance of the generic Action<T,T>. // // TODO this allocates a new 'Action' for every SyncVar hook call. // we should allocate it once and store it somewhere in the future. // hooks are only called on the client though, so it's not too bad for now. TypeReference actionRef = assembly.MainModule.ImportReference(typeof(Action <,>)); GenericInstanceType genericInstance = actionRef.MakeGenericInstanceType(fd.FieldType, fd.FieldType); worker.Emit(OpCodes.Newobj, weaverTypes.ActionT_T.MakeHostInstanceGeneric(assembly.MainModule, genericInstance)); } // pass 'null' as hook else { worker.Emit(OpCodes.Ldnull); } // call GeneratedSyncVarSetter<T>. // special cases for GameObject/NetworkIdentity/NetworkBehaviour // passing netId too for persistence. if (fd.FieldType.Is <UnityEngine.GameObject>()) { // GameObject setter needs one more parameter: netId field ref worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, netFieldId); worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_GameObject); } else if (fd.FieldType.Is <NetworkIdentity>()) { // NetworkIdentity setter needs one more parameter: netId field ref worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, netFieldId); worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_NetworkIdentity); } // TODO this only uses the persistent netId for types DERIVED FROM NB. // not if the type is just 'NetworkBehaviour'. // this is what original implementation did too. fix it after. else if (fd.FieldType.IsDerivedFrom <NetworkBehaviour>()) { // NetworkIdentity setter needs one more parameter: netId field ref // (actually its a NetworkBehaviourSyncVar type) worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, netFieldId); // make generic version of GeneratedSyncVarSetter_NetworkBehaviour<T> MethodReference getFunc = weaverTypes.generatedSyncVarSetter_NetworkBehaviour_T.MakeGeneric(assembly.MainModule, fd.FieldType); worker.Emit(OpCodes.Call, getFunc); } else { // make generic version of GeneratedSyncVarSetter<T> MethodReference generic = weaverTypes.generatedSyncVarSetter.MakeGeneric(assembly.MainModule, fd.FieldType); worker.Emit(OpCodes.Call, generic); } worker.Append(endOfMethod); worker.Emit(OpCodes.Ret); set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType)); set.SemanticsAttributes = MethodSemanticsAttributes.Setter; return(set); }
static bool CompareTypes(TypeReference iType, TypeReference tType) { if (iType.IsGenericParameter) { return(true); } if (iType.IsArray) { if (!tType.IsArray) { return(false); } return(CompareTypes(iType.GetElementType(), tType.GetElementType())); } if (iType.IsByReference) { if (!tType.IsByReference) { return(false); } return(CompareTypes(iType.GetElementType(), tType.GetElementType())); } if (iType.Name != tType.Name) { return(false); } if (iType.Namespace != tType.Namespace) { return(false); } TypeDefinition iTypeDef = iType.Resolve(); if (iTypeDef == null) { return(false); } TypeDefinition tTypeDef = tType.Resolve(); if (tTypeDef == null) { return(false); } if (iTypeDef.Module.FullyQualifiedName != tTypeDef.Module.FullyQualifiedName) { return(false); } if (iType is Mono.Cecil.GenericInstanceType && tType is Mono.Cecil.GenericInstanceType) { GenericInstanceType iGType = iType as GenericInstanceType; GenericInstanceType tGType = tType as GenericInstanceType; if (iGType.GenericArguments.Count != tGType.GenericArguments.Count) { return(false); } for (int i = 0; i < iGType.GenericArguments.Count; i++) { if (iGType.GenericArguments [i].IsGenericParameter) { continue; } if (!CompareTypes(iGType.GenericArguments [i], tGType.GenericArguments [i])) { return(false); } } } return(true); }
static MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable, int recursionCount) { GenericInstanceType genericInstance = (GenericInstanceType)variable; TypeReference elementType = genericInstance.GenericArguments[0]; MethodReference elementReadFunc = GetReadFunc(elementType, recursionCount + 1); if (elementReadFunc == null) { return(null); } string functionName = "_ReadArraySegment_" + variable.GetElementType().Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new reader for this type MethodDefinition readerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, variable); readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); // int lengh readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); // T[] array readerFunc.Body.Variables.Add(new VariableDefinition(elementType.MakeArrayType())); // int i; readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); readerFunc.Body.InitLocals = true; ILProcessor worker = readerFunc.Body.GetILProcessor(); // int length = reader.ReadPackedInt32(); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, GetReadFunc(Weaver.int32Type))); worker.Append(worker.Create(OpCodes.Stloc_0)); // T[] array = new int[length] worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Newarr, elementType)); worker.Append(worker.Create(OpCodes.Stloc_1)); // loop through array and deserialize each element // generates code like this // for (int i=0; i< length ; i++) // { // value[i] = reader.ReadXXX(); // } worker.Append(worker.Create(OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Stloc_2)); Instruction labelHead = worker.Create(OpCodes.Nop); worker.Append(worker.Create(OpCodes.Br, labelHead)); // loop body Instruction labelBody = worker.Create(OpCodes.Nop); worker.Append(labelBody); { // value[i] = reader.ReadT(); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldelema, elementType)); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, elementReadFunc)); worker.Append(worker.Create(OpCodes.Stobj, elementType)); } worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Add)); worker.Append(worker.Create(OpCodes.Stloc_2)); // loop while check worker.Append(labelHead); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Blt, labelBody)); // return new ArraySegment<T>(array); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Newobj, Weaver.ArraySegmentConstructorReference.MakeHostInstanceGeneric(genericInstance))); worker.Append(worker.Create(OpCodes.Ret)); return(readerFunc); }
public void Execute() { var reactiveUI = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault(); var helpers = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "Reactive.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault(); var reactiveObject = new TypeReference("ReactiveUI", "IReactiveObject", ModuleDefinition, reactiveUI); var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType != null && reactiveObject.IsAssignableFrom(x.BaseType)).ToArray(); var reactivePropertyExtensions = ModuleDefinition.FindType("Reactive.Fody.Helpers", "ReactivePropertyExtensions", helpers).Resolve(); if (reactivePropertyExtensions == null) { throw new Exception("reactivePropertyExtensions is null"); } var raiseAndSetIfChangedMethod = ModuleDefinition.ImportReference(reactivePropertyExtensions.Methods.Single(x => x.Name == "RaiseAndSetIfChanged")); if (raiseAndSetIfChangedMethod == null) { throw new Exception("raiseAndSetIfChangedMethod is null"); } var reactiveAttribute = ModuleDefinition.FindType("Reactive.Fody.Helpers", "ReactiveAttribute", helpers); if (reactiveAttribute == null) { throw new Exception("reactiveAttribute is null"); } var reactiveObjectExtensions = new TypeReference("ReactiveUI", "IReactiveObjectExtensions", ModuleDefinition, reactiveUI).Resolve(); if (reactiveObjectExtensions == null) { throw new Exception("reactiveObjectExtensions is null"); } var raisePropertyChangedMethod = ModuleDefinition.ImportReference(reactiveObjectExtensions.Methods.Single(x => x.Name == "RaisePropertyChanged")); if (raisePropertyChangedMethod == null) { throw new Exception("raisePropertyChangedMethod is null"); } foreach (var targetType in targetTypes) { var setMethodByGetMethods = targetType.Properties .Where(x => x.SetMethod != null && x.GetMethod != null && x.IsDefined(reactiveAttribute)) .ToDictionary(x => x.GetMethod, x => x.SetMethod); foreach (var property in targetType.Properties.Where(x => x.IsDefined(reactiveAttribute)).ToArray()) { TypeReference genericTargetType = targetType; if (targetType.HasGenericParameters) { var genericDeclaration = new GenericInstanceType(targetType); foreach (var parameter in targetType.GenericParameters) { genericDeclaration.GenericArguments.Add(parameter); } genericTargetType = genericDeclaration; } MethodDefinition[] getMethods; if (property.SetMethod == null && property.GetMethod.TryGetMethodDependencies(out getMethods)) { var setMethodsForGetInstructions = getMethods .Where(x => setMethodByGetMethods.ContainsKey(x)) .Select(x => setMethodByGetMethods[x]) .ToArray(); if (!setMethodsForGetInstructions.Any()) { LogError($"Get only Property {property.DeclaringType.FullName}.{property.Name} has no supported dependent properties. " + $"Only dependent auto properties decorated with the [Reactive] attribute can be weaved to raise property change on {property.Name}"); } var raisePropertyChangedMethodReference = raisePropertyChangedMethod.MakeGenericMethod(genericTargetType); foreach (var method in setMethodsForGetInstructions) { method.Body.Emit(il => { var last = method.Body.Instructions.Last(i => i.OpCode == OpCodes.Ret); il.InsertBefore(last, il.Create(OpCodes.Ldarg_0)); il.InsertBefore(last, il.Create(OpCodes.Ldstr, property.Name)); il.InsertBefore(last, il.Create(OpCodes.Call, raisePropertyChangedMethodReference)); }); } // Move on to next property for the target type continue; } if (property.SetMethod == null) { LogError($"Property {property.DeclaringType.FullName}.{property.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [Reactive]"); continue; } // Declare a field to store the property value var field = new FieldDefinition("$" + property.Name, FieldAttributes.Private, property.PropertyType); targetType.Fields.Add(field); // Remove old field (the generated backing field for the auto property) var oldField = (FieldReference)property.GetMethod.Body.Instructions.Where(x => x.Operand is FieldReference).Single().Operand; var oldFieldDefinition = oldField.Resolve(); targetType.Fields.Remove(oldFieldDefinition); // See if there exists an initializer for the auto-property var constructors = targetType.Methods.Where(x => x.IsConstructor); foreach (var constructor in constructors) { var fieldAssignment = constructor.Body.Instructions.SingleOrDefault(x => Equals(x.Operand, oldFieldDefinition) || Equals(x.Operand, oldField)); if (fieldAssignment != null) { // Replace field assignment with a property set (the stack semantics are the same for both, // so happily we don't have to manipulate the bytecode any further.) var setterCall = constructor.Body.GetILProcessor().Create(property.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, property.SetMethod); constructor.Body.GetILProcessor().Replace(fieldAssignment, setterCall); } } // Build out the getter which simply returns the value of the generated field property.GetMethod.Body = new MethodBody(property.GetMethod); property.GetMethod.Body.Emit(il => { il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldfld, field.BindDefinition(targetType)); // pop -> this.$PropertyName il.Emit(OpCodes.Ret); // Return the field value that is lying on the stack }); var methodReference = raiseAndSetIfChangedMethod.MakeGenericMethod(genericTargetType, property.PropertyType); // Build out the setter which fires the RaiseAndSetIfChanged method if (property.SetMethod == null) { throw new Exception("[Reactive] is decorating " + property.DeclaringType.FullName + "." + property.Name + ", but the property has no setter so there would be nothing to react to. Consider removing the attribute."); } property.SetMethod.Body = new MethodBody(property.SetMethod); property.SetMethod.Body.Emit(il => { RaiseAndSetIfChanged(methodReference, targetType, field, il, property.Name); }); } } }
private static string NonUniqueShortNameFor(GenericInstanceType type) => (NonUniqueShortNameFor(type.ElementType) + "_gen");
static void ProcessMethod(MethodDefinition method, HashSet <TypeReference> typeset) { // this is needed in case we return an enum, a struct or something mapped // to p/invoke (i.e. no ctor called). We also need to check for arrays. TypeReference t = method.ReturnType; AddType(typeset, t); if (method.HasParameters) { // an "out" from a p/invoke must be flagged foreach (ParameterDefinition parameter in method.Parameters) { // we don't want the reference (&) on the type t = parameter.ParameterType.GetElementType(); AddType(typeset, t); } } if (!method.HasBody) { return; } MethodBody body = method.Body; if (body.HasVariables) { // add every type of variables we use foreach (VariableDefinition variable in body.Variables) { t = variable.VariableType; AddType(typeset, t); } } // add every type we create or refer to (e.g. loading fields from an enum) foreach (Instruction ins in body.Instructions) { if (ins.Operand == null) { continue; } t = ins.Operand as TypeReference; if (t == null) { MethodReference m = ins.Operand as MethodReference; if (m != null) { t = m.DeclaringType; GenericInstanceType generic = (t as GenericInstanceType); if (generic != null) { t = generic.GetElementType(); } } else { FieldReference f = ins.Operand as FieldReference; if (f != null) { t = f.DeclaringType; } } } if (t != null) { AddType(typeset, t); } } }
private static void GenerateNormal(MethodDefinition method, TypeReference enumerable, GenericInstanceType selector, GenericInstanceType func) { method.Parameters.Add(new ParameterDefinition("@this", ParameterAttributes.In, new ByReferenceType(enumerable)) { CustomAttributes = { Helper.GetSystemRuntimeCompilerServicesIsReadOnlyAttributeTypeReference() } }); method.Parameters.Add(new ParameterDefinition("selector", ParameterAttributes.None, func)); var body = method.Body; body.Variables.Add(new VariableDefinition(selector)); body.GetILProcessor() .LoadFuncArgumentAndStoreToLocalVariableField(1, 0) .LdArg(0) .LdLocA(0) .NewObj(method.ReturnType.FindMethod(".ctor", 2)) .Ret(); }
private static void GenerateSpecial(MethodDefinition method, TypeReference baseEnumerable, GenericInstanceType enumerable, GenericInstanceType selector, GenericInstanceType func) { method.Parameters.Add(new ParameterDefinition("@this", ParameterAttributes.None, baseEnumerable)); method.Parameters.Add(new ParameterDefinition("selector", ParameterAttributes.None, func)); var body = method.Body; body.InitLocals = true; body.Variables.Add(new VariableDefinition(enumerable)); body.Variables.Add(new VariableDefinition(selector)); body.GetILProcessor() .LdLocA(0) .LdArg(0) .Call(enumerable.FindMethod(".ctor", 1)) .LoadFuncArgumentAndStoreToLocalVariableField(1, 1) .LdLocA(0) .LdLocA(1) .NewObj(method.ReturnType.FindMethod(".ctor", 2)) .Ret(); }
/// <summary> /// This method resolves a type. This method ignores the methods and fields. You have to /// resolve them manually. /// </summary> /// <param name="hostModule">The module in which the changes are made.</param> /// <param name="type">The type to resolve.</param> /// <param name="AddedClasses">Newly added classes to lookup while resolving.</param> /// <param name="TypesMap">A map of types to lookup while resolving.</param> /// <returns></returns> protected static TypeReference Resolve( ModuleDefinition hostModule, TypeReference type, Dictionary <TypeReference, TypeDefinition> AddedClasses, Dictionary <TypeReference, TypeReference> TypesMap) { if (type is GenericInstanceType) { GenericInstanceType gType = (GenericInstanceType)type; GenericInstanceType nType = new GenericInstanceType(Resolve(hostModule, gType.ElementType, AddedClasses, TypesMap)); foreach (TypeReference t in gType.GenericArguments) { nType.GenericArguments.Add(Resolve(hostModule, t, AddedClasses, TypesMap)); } return(nType); } if (type == null || type is GenericParameter || (type.IsArray && type.GetElementType() is GenericParameter)) { return(type); } if (TypesMap.ContainsKey(type)) { return(hostModule.Import(TypesMap[type])); } foreach (TypeReference addedType in AddedClasses.Keys) { if (addedType == type) { return(hostModule.Import(AddedClasses[addedType])); } } if (type.Module != hostModule) { TypeDefinition t = hostModule.GetType(type.FullName); if (t != null) { return((TypeReference)t); } if (hostModule == null || type == null) { return(type); } else { try { return(hostModule.Import(type)); } catch (Exception e) { System.Console.WriteLine(type.GetElementType()); System.Console.WriteLine(type.GetType().FullName); throw e; } } } else { return(type); } }
internal static TypeReference ResolveType(TypeReference original, Mono.Collections.Generic.Collection<GenericParameter> parameters, Mono.Collections.Generic.Collection<TypeReference> arguments) { TypeSpecification spec = original as TypeSpecification; ArrayType array = original as ArrayType; ByReferenceType reference = original as ByReferenceType; GenericInstanceType genericType = original as GenericInstanceType; if (parameters.Count != arguments.Count) throw new System.ArgumentException ("Parameters and Arguments must have the same number of elements."); if (spec != null) { TypeReference resolved = ResolveType (spec.ElementType, parameters, arguments); if (genericType != null) { GenericInstanceType result = new GenericInstanceType (genericType.ElementType); bool found; for (int i = 0; i < genericType.ElementType.GenericParameters.Count; i++) { found = false; for (int k = 0; k < parameters.Count; k++) { if (genericType.ElementType.GenericParameters [i].Name == parameters [k].Name) { found = true; result.GenericArguments.Add (arguments [k]); break; } } if (!found) result.GenericArguments.Add (genericType.ElementType.GenericParameters [i]); } return result; } if (resolved == spec.ElementType) return spec; if (array != null) { return new ArrayType (resolved, array.Dimensions.Count); } else if (reference != null) { return new ByReferenceType (resolved); } else { throw new System.NotImplementedException (); } } else { for (int i = 0; i < parameters.Count; i++) { if (parameters [i] == original) { return arguments [i]; } } return original; } }
public static bool ExpandPositionalGenericParameters(TypeReference type, out TypeReference expanded) { var gp = type as GenericParameter; var git = type as GenericInstanceType; var at = type as ArrayType; var byref = type as ByReferenceType; TypeReference _expanded; if (gp != null) { if (IsPositionalGenericParameter(gp)) { var ownerType = gp.Owner as TypeReference; var ownerMethod = gp.Owner as MethodReference; if (ownerType != null) { var resolvedOwnerType = ownerType.Resolve(); if (resolvedOwnerType == null) { expanded = type; return(false); } expanded = resolvedOwnerType.GenericParameters[int.Parse(gp.Name.Replace("!", ""))]; return(true); } else if (ownerMethod != null) { var resolvedOwnerMethod = ownerMethod.Resolve(); if (resolvedOwnerMethod == null) { expanded = type; return(false); } expanded = resolvedOwnerMethod.GenericParameters[int.Parse(gp.Name.Replace("!", ""))]; return(true); } else { throw new NotImplementedException("Unknown positional generic parameter type"); } } } if (git != null) { var elt = git.ElementType; if (ContainsPositionalGenericParameter(elt) || git.GenericArguments.Any(ContainsPositionalGenericParameter)) { ExpandPositionalGenericParameters(elt, out _expanded); var result = new GenericInstanceType(_expanded); foreach (var ga in git.GenericArguments) { ExpandPositionalGenericParameters(ga, out _expanded); result.GenericArguments.Add(_expanded); } expanded = result; return(true); } } if (at != null) { ExpandPositionalGenericParameters(at.ElementType, out _expanded); } if (byref != null) { ExpandPositionalGenericParameters(byref.ElementType, out _expanded); } expanded = type; return(false); }
void InitializeBaseType() { if (definition != null && definition.BaseType != null) { bool specialProcess = false; List <int> spIdx = null; if (definition.BaseType.IsGenericInstance) { GenericInstanceType git = definition.BaseType as GenericInstanceType; var elementType = appdomain.GetType(git.ElementType, this, null); if (elementType is CLRType) { for (int i = 0; i < git.GenericArguments.Count; i++) { var ga = git.GenericArguments[i]; if (ga == typeRef) { specialProcess = true; if (spIdx == null) { spIdx = new List <int>(); } spIdx.Add(i); } } } } if (specialProcess) { //如果泛型参数是自身,则必须要特殊处理,否则会StackOverflow var elementType = appdomain.GetType(((GenericInstanceType)definition.BaseType).ElementType, this, null); foreach (var i in appdomain.CrossBindingAdaptors) { if (i.Key.IsGenericType && !i.Key.IsGenericTypeDefinition) { var gd = i.Key.GetGenericTypeDefinition(); if (gd == elementType.TypeForCLR) { var ga = i.Key.GetGenericArguments(); bool match = true; foreach (var j in spIdx) { if (ga[j] != i.Value.AdaptorType) { match = false; break; } } if (match) { baseType = i.Value; break; } } } } if (baseType == null) { throw new TypeLoadException("Cannot find Adaptor for:" + definition.BaseType.FullName); } } else { baseType = appdomain.GetType(definition.BaseType, this, null); if (baseType is CLRType) { if (baseType.TypeForCLR == typeof(Enum) || baseType.TypeForCLR == typeof(object) || baseType.TypeForCLR == typeof(ValueType) || baseType.TypeForCLR == typeof(System.Enum)) {//都是这样,无所谓 baseType = null; } else if (baseType.TypeForCLR == typeof(MulticastDelegate)) { baseType = null; isDelegate = true; } else { CrossBindingAdaptor adaptor; if (appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR, out adaptor)) { baseType = adaptor; } else { throw new TypeLoadException("Cannot find Adaptor for:" + baseType.TypeForCLR.ToString()); } //继承了其他系统类型 //env.logger.Log_Error("ScriptType:" + Name + " Based On a SystemType:" + BaseType.Name); //HasSysBase = true; //throw new Exception("不得继承系统类型,脚本类型系统和脚本类型系统是隔离的"); } } } } var curBase = baseType; while (curBase is ILType) { curBase = curBase.BaseType; } firstCLRBaseType = curBase; baseTypeInitialized = true; }
protected override void DisposeCore() { retType = null; }
/// <summary> /// Replace generic parameters with actual arguments /// </summary> private MonoTypeContext ResolveGenericParameter() { switch (Type.etype) { case ElementType.Var: case ElementType.MVar: { GenericParameter parameter = (GenericParameter)Type; TypeReference resolvedType = Arguments[parameter]; return(new MonoTypeContext(resolvedType)); } case ElementType.Array: { ArrayType array = (ArrayType)Type; MonoTypeContext arrayContext = new MonoTypeContext(array.ElementType, Arguments); MonoTypeContext resolvedContext = arrayContext.ResolveGenericParameter(); ArrayType newArray = new ArrayType(resolvedContext.Type, array.Rank); if (array.Rank > 1) { for (int i = 0; i < array.Rank; i++) { newArray.Dimensions[i] = array.Dimensions[i]; } } return(new MonoTypeContext(newArray, Arguments)); } case ElementType.GenericInst: { GenericInstanceType genericInstance = (GenericInstanceType)Type; GenericInstanceType newInstance = new GenericInstanceType(genericInstance.ElementType); foreach (TypeReference argument in genericInstance.GenericArguments) { MonoTypeContext argumentContext = new MonoTypeContext(argument, Arguments); MonoTypeContext resolvedArgument = argumentContext.Resolve(); newInstance.GenericArguments.Add(resolvedArgument.Type); } return(new MonoTypeContext(newInstance, Arguments)); } case ElementType.ByRef: { ByReferenceType reference = (ByReferenceType)Type; MonoTypeContext refContext = new MonoTypeContext(reference.ElementType, Arguments); MonoTypeContext resolvedContext = refContext.ResolveGenericParameter(); ByReferenceType newReference = new ByReferenceType(resolvedContext.Type); return(new MonoTypeContext(newReference, Arguments)); } case ElementType.Ptr: { PointerType pointer = (PointerType)Type; MonoTypeContext ptrContext = new MonoTypeContext(pointer.ElementType, Arguments); MonoTypeContext resolvedContext = ptrContext.ResolveGenericParameter(); PointerType newPointer = new PointerType(resolvedContext.Type); return(new MonoTypeContext(newPointer, Arguments)); } case ElementType.Pinned: { PinnedType pinned = (PinnedType)Type; MonoTypeContext pinContext = new MonoTypeContext(pinned.ElementType, Arguments); MonoTypeContext resolvedContext = pinContext.ResolveGenericParameter(); PinnedType newPinned = new PinnedType(resolvedContext.Type); return(new MonoTypeContext(newPinned, Arguments)); } case ElementType.FnPtr: { FunctionPointerType funcPtr = (FunctionPointerType)Type; FunctionPointerType newFuncPtr = new FunctionPointerType(); newFuncPtr.HasThis = funcPtr.HasThis; newFuncPtr.ExplicitThis = funcPtr.ExplicitThis; newFuncPtr.CallingConvention = funcPtr.CallingConvention; MonoTypeContext returnContext = new MonoTypeContext(funcPtr.ReturnType, Arguments); MonoTypeContext resolvedReturn = returnContext.Resolve(); newFuncPtr.ReturnType = resolvedReturn.Type; foreach (ParameterDefinition param in funcPtr.Parameters) { MonoTypeContext paramContext = new MonoTypeContext(param.ParameterType, Arguments); MonoTypeContext resolvedParam = paramContext.Resolve(); ParameterDefinition newParameter = new ParameterDefinition(param.Name, param.Attributes, resolvedParam.Type); newFuncPtr.Parameters.Add(newParameter); } return(new MonoTypeContext(newFuncPtr, Arguments)); } default: throw new Exception($"Unknown generic parameter container {Type}"); } }
/// <exception cref="GenerateWriterException">Throws when writer could not be generated for type</exception> static MethodReference GenerateWriter(TypeReference variableReference) { if (variableReference.IsByReference) { throw new GenerateWriterException($"Cannot pass {variableReference.Name} by reference", variableReference); } // Arrays are special, if we resolve them, we get the element type, // eg int[] resolves to int // therefore process this before checks below if (variableReference.IsArray) { if (variableReference.IsMultidimensionalArray()) { throw new GenerateWriterException($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference); } TypeReference elementType = variableReference.GetElementType(); return(GenerateGenericWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArray))); } if (variableReference.Resolve()?.IsEnum ?? false) { // serialize enum as their base type return(GenerateEnumWriteFunc(variableReference)); } // check for collections or nullable if (variableReference.Is(typeof(Nullable <>))) { GenericInstanceType genericInstance = (GenericInstanceType)variableReference; TypeReference elementType = genericInstance.GenericArguments[0]; return(GenerateGenericWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteNullable))); } if (variableReference.Is(typeof(ArraySegment <>))) { GenericInstanceType genericInstance = (GenericInstanceType)variableReference; TypeReference elementType = genericInstance.GenericArguments[0]; return(GenerateGenericWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArraySegment))); } if (variableReference.Is(typeof(List <>))) { GenericInstanceType genericInstance = (GenericInstanceType)variableReference; TypeReference elementType = genericInstance.GenericArguments[0]; return(GenerateGenericWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteList))); } if (variableReference.IsDerivedFrom <NetworkBehaviour>()) { return(GetNetworkBehaviourWriter(variableReference)); } // check for invalid types TypeDefinition variableDefinition = variableReference.Resolve(); if (variableDefinition == null) { throw new GenerateWriterException($"{variableReference.Name} is not a supported type. Use a supported type or provide a custom writer", variableReference); } if (variableDefinition.IsDerivedFrom <UnityEngine.Component>()) { throw new GenerateWriterException($"Cannot generate writer for component type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); } if (variableReference.Is <UnityEngine.Object>()) { throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); } if (variableReference.Is <UnityEngine.ScriptableObject>()) { throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); } if (variableDefinition.HasGenericParameters) { throw new GenerateWriterException($"Cannot generate writer for generic type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); } if (variableDefinition.IsInterface) { throw new GenerateWriterException($"Cannot generate writer for interface {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); } if (variableDefinition.IsAbstract) { throw new GenerateWriterException($"Cannot generate writer for abstract class {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); } // generate writer for class/struct return(GenerateClassOrStructWriterFunction(variableReference)); }
private static GenericInstanceType MakeGenericType(GenericInstanceType genericInstanceProvider, GenericInstanceType type) { var result = new GenericInstanceType(type.ElementType); for (var i = 0; i < type.GenericArguments.Count; ++i) { result.GenericArguments.Add(InflateGenericType(genericInstanceProvider, type.GenericArguments [i])); } return(result); }
public TypeReference Resolve(TypeReference typeReference, bool resolveGenericParameters) { if (IsDummy()) { return(typeReference); } if (m_TypeDefinitionContext != null && m_TypeDefinitionContext.GenericArguments.Contains(typeReference)) { return(typeReference); } if (m_MethodDefinitionContext != null && m_MethodDefinitionContext.GenericArguments.Contains(typeReference)) { return(typeReference); } switch (typeReference) { case GenericParameter genericParameter when m_TypeDefinitionContext != null && m_TypeDefinitionContext.GenericArguments.Contains(genericParameter): return(genericParameter); case GenericParameter genericParameter when m_MethodDefinitionContext != null && m_MethodDefinitionContext.GenericArguments.Contains(genericParameter): return(genericParameter); case GenericParameter genericParameter: return(ResolveGenericParameter(genericParameter)); case ArrayType arrayType: return(new ArrayType(Resolve(arrayType.ElementType), arrayType.Rank)); case PointerType pointerType: return(new PointerType(Resolve(pointerType.ElementType))); case ByReferenceType byReferenceType: return(new ByReferenceType(Resolve(byReferenceType.ElementType))); case PinnedType pinnedType: return(new PinnedType(Resolve(pinnedType.ElementType))); case GenericInstanceType genericInstanceType: { var newGenericInstanceType = new GenericInstanceType(genericInstanceType.ElementType); foreach (var genericArgument in genericInstanceType.GenericArguments) { newGenericInstanceType.GenericArguments.Add(Resolve(genericArgument)); } newGenericInstanceType.MetadataToken = genericInstanceType.MetadataToken; return(newGenericInstanceType); } case RequiredModifierType requiredModType: return(new RequiredModifierType(requiredModType.ModifierType, Resolve(requiredModType.ElementType, resolveGenericParameters))); case OptionalModifierType optionalModType: return(Resolve(optionalModType.ElementType, resolveGenericParameters)); } if (resolveGenericParameters) { if (typeReference is TypeDefinition typeDefinition && typeDefinition.HasGenericParameters) { var newGenericInstanceType = new GenericInstanceType(typeDefinition); foreach (var gp in typeDefinition.GenericParameters) { newGenericInstanceType.GenericArguments.Add(Resolve(gp)); } return(newGenericInstanceType); } } if (typeReference is TypeSpecification) { throw new NotSupportedException($"The type {typeReference.FullName} cannot be resolved correctly."); } return(typeReference); }
public static TypeReference InflateGenericType(GenericInstanceType genericInstanceProvider, TypeReference typeToInflate) { var arrayType = typeToInflate as ArrayType; if (arrayType != null) { var inflatedElementType = InflateGenericType(genericInstanceProvider, arrayType.ElementType); if (inflatedElementType != arrayType.ElementType) { return(new ArrayType(inflatedElementType, arrayType.Rank)); } return(arrayType); } var genericInst = typeToInflate as GenericInstanceType; if (genericInst != null) { return(MakeGenericType(genericInstanceProvider, genericInst)); } var genericParameter = typeToInflate as GenericParameter; if (genericParameter != null) { if (genericParameter.Owner is MethodReference) { return(genericParameter); } var elementType = genericInstanceProvider.ElementType.Resolve(); var parameter = elementType.GenericParameters.Single(p => p == genericParameter); return(genericInstanceProvider.GenericArguments [parameter.Position]); } var functionPointerType = typeToInflate as FunctionPointerType; if (functionPointerType != null) { var result = new FunctionPointerType(); result.ReturnType = InflateGenericType(genericInstanceProvider, functionPointerType.ReturnType); for (int i = 0; i < functionPointerType.Parameters.Count; i++) { var inflatedParameterType = InflateGenericType(genericInstanceProvider, functionPointerType.Parameters [i].ParameterType); result.Parameters.Add(new ParameterDefinition(inflatedParameterType)); } return(result); } var modifierType = typeToInflate as IModifierType; if (modifierType != null) { var modifier = InflateGenericType(genericInstanceProvider, modifierType.ModifierType); var elementType = InflateGenericType(genericInstanceProvider, modifierType.ElementType); if (modifierType is OptionalModifierType) { return(new OptionalModifierType(modifier, elementType)); } return(new RequiredModifierType(modifier, elementType)); } var pinnedType = typeToInflate as PinnedType; if (pinnedType != null) { var elementType = InflateGenericType(genericInstanceProvider, pinnedType.ElementType); if (elementType != pinnedType.ElementType) { return(new PinnedType(elementType)); } return(pinnedType); } var pointerType = typeToInflate as PointerType; if (pointerType != null) { var elementType = InflateGenericType(genericInstanceProvider, pointerType.ElementType); if (elementType != pointerType.ElementType) { return(new PointerType(elementType)); } return(pointerType); } var byReferenceType = typeToInflate as ByReferenceType; if (byReferenceType != null) { var elementType = InflateGenericType(genericInstanceProvider, byReferenceType.ElementType); if (elementType != byReferenceType.ElementType) { return(new ByReferenceType(elementType)); } return(byReferenceType); } var sentinelType = typeToInflate as SentinelType; if (sentinelType != null) { var elementType = InflateGenericType(genericInstanceProvider, sentinelType.ElementType); if (elementType != sentinelType.ElementType) { return(new SentinelType(elementType)); } return(sentinelType); } return(typeToInflate); }
static GenericInstanceType ResolveIfNeeded(IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, GenericInstanceType genericInstanceType1) { if (!genericInstanceType1.ContainsGenericParameters()) { return(genericInstanceType1); } var newGenericInstance = new GenericInstanceType(genericInstanceType1.ElementType); foreach (var genericArgument in genericInstanceType1.GenericArguments) { if (!genericArgument.IsGenericParameter) { newGenericInstance.GenericArguments.Add(ResolveIfNeeded(genericInstanceMethod, genericInstanceType, genericArgument)); continue; } var genParam = (GenericParameter)genericArgument; switch (genParam.Type) { case GenericParameterType.Type: { if (genericInstanceType == null) { throw new NotSupportedException(); } newGenericInstance.GenericArguments.Add(genericInstanceType.GenericArguments[genParam.Position]); } break; case GenericParameterType.Method: { if (genericInstanceMethod == null) { newGenericInstance.GenericArguments.Add(genParam); } else { newGenericInstance.GenericArguments.Add(genericInstanceMethod.GenericArguments[genParam.Position]); } } break; } } return(newGenericInstance); }
public TypeReference ImportReference(Type type, IGenericParameterProvider context) { if (CachedTypes.TryGetValue(type, out TypeReference typeRef)) { return(typeRef); } if (UseDefault) { return(CachedTypes[type] = Default.ImportReference(type, context)); } if (type.HasElementType) { if (type.IsByRef) { return(CachedTypes[type] = new ByReferenceType(ImportReference(type.GetElementType(), context))); } if (type.IsPointer) { return(CachedTypes[type] = new PointerType(ImportReference(type.GetElementType(), context))); } if (type.IsArray) { ArrayType at = new ArrayType(ImportReference(type.GetElementType(), context), type.GetArrayRank()); if (type != type.GetElementType().MakeArrayType()) { // Non-SzArray // TODO: Find a way to get the bounds without instantiating the array type! /* * Array a = Array.CreateInstance(type, new int[type.GetArrayRank()]); * if ( * at.Rank > 1 * && a.IsFixedSize * ) { * for (int i = 0; i < at.Rank; i++) * at.Dimensions[i] = new ArrayDimension(a.GetLowerBound(i), a.GetUpperBound(i)); * } */ // For now, always assume [0...,0..., // Array.CreateInstance only accepts lower bounds anyway. for (int i = 0; i < at.Rank; i++) { at.Dimensions[i] = new ArrayDimension(0, null); } } return(CachedTypes[type] = at); } } bool isGeneric = type.IsGenericType; if (isGeneric && !type.IsGenericTypeDefinition) { GenericInstanceType git = new GenericInstanceType(ImportReference(type.GetGenericTypeDefinition(), context)); foreach (Type arg in type.GetGenericArguments()) { git.GenericArguments.Add(ImportReference(arg, context)); } return(git); } if (type.IsGenericParameter) { return(CachedTypes[type] = ImportGenericParameter(type, context)); } if (ElementTypes.TryGetValue(type, out typeRef)) { return(CachedTypes[type] = typeRef); } typeRef = new TypeReference( string.Empty, type.Name, Module, ImportReference(type.Assembly.GetName()), type.IsValueType ); if (type.IsNested) { typeRef.DeclaringType = ImportReference(type.DeclaringType, context); } else if (type.Namespace != null) { typeRef.Namespace = type.Namespace; } if (type.IsGenericType) { foreach (Type param in type.GetGenericArguments()) { typeRef.GenericParameters.Add(new GenericParameter(param.Name, typeRef)); } } return(CachedTypes[type] = typeRef); }
/// <summary> /// Executes this instance. /// </summary> /// <exception cref="Exception"> /// reactiveObjectExtensions is null /// or /// raisePropertyChangedMethod is null /// or /// reactiveDecoratorAttribute is null. /// </exception> public void Execute() { var reactiveUI = ModuleDefinition?.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault(); if (reactiveUI == null) { LogInfo?.Invoke("Could not find assembly: ReactiveUI (" + string.Join(", ", ModuleDefinition?.AssemblyReferences.Select(x => x.Name)) + ")"); return; } LogInfo?.Invoke($"{reactiveUI.Name} {reactiveUI.Version}"); var helpers = ModuleDefinition?.AssemblyReferences.Where(x => x.Name == "ReactiveUI.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault(); if (helpers == null) { LogInfo?.Invoke("Could not find assembly: ReactiveUI.Fody.Helpers (" + string.Join(", ", ModuleDefinition?.AssemblyReferences.Select(x => x.Name)) + ")"); return; } LogInfo?.Invoke($"{helpers.Name} {helpers.Version}"); var reactiveObject = new TypeReference("ReactiveUI", "IReactiveObject", ModuleDefinition, reactiveUI); var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType != null && reactiveObject.IsAssignableFrom(x.BaseType)).ToArray(); var reactiveObjectExtensions = new TypeReference("ReactiveUI", "IReactiveObjectExtensions", ModuleDefinition, reactiveUI).Resolve(); if (reactiveObjectExtensions == null) { throw new Exception("reactiveObjectExtensions is null"); } var raisePropertyChangedMethod = ModuleDefinition?.ImportReference(reactiveObjectExtensions.Methods.Single(x => x.Name == "RaisePropertyChanged")); if (raisePropertyChangedMethod == null) { throw new Exception("raisePropertyChangedMethod is null"); } var reactiveDependencyAttribute = ModuleDefinition?.FindType("ReactiveUI.Fody.Helpers", "ReactiveDependencyAttribute", helpers); if (reactiveDependencyAttribute == null) { throw new Exception("reactiveDecoratorAttribute is null"); } foreach (var targetType in targetTypes.Where(x => x.Properties.Any(y => y.IsDefined(reactiveDependencyAttribute))).ToArray()) { foreach (var facadeProperty in targetType.Properties.Where(x => x.IsDefined(reactiveDependencyAttribute)).ToArray()) { // If the property already has a body then do not weave to prevent loss of instructions if (!facadeProperty.GetMethod.Body.Instructions.Any(x => x.Operand is FieldReference) || facadeProperty.GetMethod.Body.HasVariables) { LogError?.Invoke($"Property {facadeProperty.Name} is not an auto property and therefore not suitable for ReactiveDependency weaving"); continue; } var attribute = facadeProperty.CustomAttributes.First(x => x.AttributeType.FullName == reactiveDependencyAttribute.FullName); var targetNamedArgument = attribute.ConstructorArguments.FirstOrDefault(); var targetValue = targetNamedArgument.Value?.ToString(); if (string.IsNullOrEmpty(targetValue)) { LogError?.Invoke("No target property defined on the object"); continue; } if (targetType.Properties.All(x => x.Name != targetValue) && targetType.Fields.All(x => x.Name != targetValue)) { LogError?.Invoke($"dependency object property/field name '{targetValue}' not found on target type {targetType.Name}"); continue; } var objPropertyTarget = targetType.Properties.FirstOrDefault(x => x.Name == targetValue); var objFieldTarget = targetType.Fields.FirstOrDefault(x => x.Name == targetValue); var objDependencyTargetType = objPropertyTarget != null ? objPropertyTarget.PropertyType.Resolve() : objFieldTarget?.FieldType.Resolve(); if (objDependencyTargetType == null) { LogError?.Invoke("Couldn't result the dependency type"); continue; } // Look for the target property on the member obj var destinationPropertyNamedArgument = attribute.Properties.FirstOrDefault(x => x.Name == "TargetProperty"); var destinationPropertyName = destinationPropertyNamedArgument.Argument.Value?.ToString(); // If no target property was specified use this property's name as the target on the decorated object (ala a decorated property) if (string.IsNullOrEmpty(destinationPropertyName)) { destinationPropertyName = facadeProperty.Name; } if (objDependencyTargetType.Properties.All(x => x.Name != destinationPropertyName)) { LogError?.Invoke($"Target property {destinationPropertyName} on dependency of type {objDependencyTargetType.DeclaringType.Name} not found"); continue; } var destinationProperty = objDependencyTargetType.Properties.First(x => x.Name == destinationPropertyName); // The property on the facade/decorator should have a setter if (facadeProperty.SetMethod == null) { LogError?.Invoke($"Property {facadeProperty.DeclaringType.FullName}.{facadeProperty.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [ReactiveDecorator]"); continue; } // The property on the dependency should have a setter e.g. Dependency.SomeProperty = value; if (destinationProperty.SetMethod == null) { LogError?.Invoke($"Dependency object's property {destinationProperty.DeclaringType.FullName}.{destinationProperty.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [ReactiveDecorator]"); continue; } // Remove old field (the generated backing field for the auto property) var oldField = (FieldReference)facadeProperty.GetMethod.Body.Instructions.Single(x => x.Operand is FieldReference).Operand; var oldFieldDefinition = oldField.Resolve(); targetType.Fields.Remove(oldFieldDefinition); // See if there exists an initializer for the auto-property var constructors = targetType.Methods.Where(x => x.IsConstructor); foreach (var constructor in constructors) { var fieldAssignment = constructor.Body.Instructions.SingleOrDefault(x => Equals(x.Operand, oldFieldDefinition) || Equals(x.Operand, oldField)); if (fieldAssignment != null) { // Replace field assignment with a property set (the stack semantics are the same for both, // so happily we don't have to manipulate the bytecode any further.) var setterCall = constructor.Body.GetILProcessor().Create(facadeProperty.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, facadeProperty.SetMethod); constructor.Body.GetILProcessor().Replace(fieldAssignment, setterCall); } } // Build out the getter which simply returns the value of the generated field facadeProperty.GetMethod.Body = new MethodBody(facadeProperty.GetMethod); facadeProperty.GetMethod.Body.Emit(il => { il.Emit(OpCodes.Ldarg_0); if (objPropertyTarget != null) { il.Emit(objPropertyTarget.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, objPropertyTarget.GetMethod); } else { il.Emit(OpCodes.Ldfld, objFieldTarget); } il.Emit(destinationProperty.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, destinationProperty.GetMethod); il.Emit(OpCodes.Ret); }); TypeReference genericTargetType = targetType; if (targetType.HasGenericParameters) { var genericDeclaration = new GenericInstanceType(targetType); foreach (var parameter in targetType.GenericParameters) { genericDeclaration.GenericArguments.Add(parameter); } genericTargetType = genericDeclaration; } var methodReference = raisePropertyChangedMethod.MakeGenericMethod(genericTargetType); facadeProperty.SetMethod.Body = new MethodBody(facadeProperty.SetMethod); facadeProperty.SetMethod.Body.Emit(il => { il.Emit(OpCodes.Ldarg_0); if (objPropertyTarget != null) { il.Emit(objPropertyTarget.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, objPropertyTarget.GetMethod); } else { il.Emit(OpCodes.Ldfld, objFieldTarget); } il.Emit(OpCodes.Ldarg_1); il.Emit(destinationProperty.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, destinationProperty.SetMethod); // Set the nested property il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, facadeProperty.Name); // "PropertyName" il.Emit(OpCodes.Call, methodReference); // this.RaisePropertyChanged("PropertyName") il.Emit(OpCodes.Ret); }); } } }
public static void GetEnumerator(this ILProcessor processor, GenericInstanceType @this) => processor.Call(@this.FindMethod(nameof(GetEnumerator), NoParameter));
private static TypeReference InflateGenericType(GenericInstanceType genericInstanceProvider, TypeReference typeToInflate) { ArrayType type = typeToInflate as ArrayType; if (type != null) { TypeReference reference = InflateGenericType(genericInstanceProvider, type.ElementType); if (reference != type.ElementType) { return(new ArrayType(reference, type.Rank)); } return(type); } GenericInstanceType baseType = typeToInflate as GenericInstanceType; if (baseType != null) { return(MakeGenericType(genericInstanceProvider, baseType)); } GenericParameter genericParameter = typeToInflate as GenericParameter; if (genericParameter != null) { GenericParameter parameter = ResolveType(genericInstanceProvider.ElementType).GenericParameters.Single <GenericParameter>(p => p == genericParameter); return(genericInstanceProvider.GenericArguments[parameter.Position]); } FunctionPointerType type3 = typeToInflate as FunctionPointerType; if (type3 != null) { FunctionPointerType type9 = new FunctionPointerType { ReturnType = InflateGenericType(genericInstanceProvider, type3.ReturnType) }; for (int i = 0; i < type3.Parameters.Count; i++) { TypeReference parameterType = InflateGenericType(genericInstanceProvider, type3.Parameters[i].ParameterType); type9.Parameters.Add(new ParameterDefinition(parameterType)); } return(type9); } IModifierType type4 = typeToInflate as IModifierType; if (type4 != null) { TypeReference modifierType = InflateGenericType(genericInstanceProvider, type4.ModifierType); TypeReference reference4 = InflateGenericType(genericInstanceProvider, type4.ElementType); if (type4 is OptionalModifierType) { return(new OptionalModifierType(modifierType, reference4)); } return(new RequiredModifierType(modifierType, reference4)); } PinnedType type5 = typeToInflate as PinnedType; if (type5 != null) { TypeReference reference5 = InflateGenericType(genericInstanceProvider, type5.ElementType); if (reference5 != type5.ElementType) { return(new PinnedType(reference5)); } return(type5); } PointerType type6 = typeToInflate as PointerType; if (type6 != null) { TypeReference reference6 = InflateGenericType(genericInstanceProvider, type6.ElementType); if (reference6 != type6.ElementType) { return(new PointerType(reference6)); } return(type6); } ByReferenceType type7 = typeToInflate as ByReferenceType; if (type7 != null) { TypeReference reference7 = InflateGenericType(genericInstanceProvider, type7.ElementType); if (reference7 != type7.ElementType) { return(new ByReferenceType(reference7)); } return(type7); } SentinelType type8 = typeToInflate as SentinelType; if (type8 == null) { return(typeToInflate); } TypeReference reference8 = InflateGenericType(genericInstanceProvider, type8.ElementType); if (reference8 != type8.ElementType) { return(new SentinelType(reference8)); } return(type8); }
private static string GetGenericInstanceName(GenericInstanceType genericInstance) { return(GetGenericName(genericInstance.ElementType, genericInstance.GenericArguments)); }
private static MethodDefinition GetImplementedMethodFromGenericInstanceType(this MethodDefinition self, GenericInstanceType type) { TypeDefinition typeDef = type.Resolve(); if (typeDef == null) { return null; } foreach (MethodDefinition method in typeDef.Methods) { if (method.Name == self.Name) { if (method.HasParameters && self.HasParameters && method.Parameters.Count == self.Parameters.Count) { if (method.ReturnType.IsGenericParameter) { int parameterPosition = (method.ReturnType as GenericParameter).Position; TypeReference genericArgument; if (!type.PostionToArgument.TryGetValue(parameterPosition, out genericArgument)) { continue; } if (genericArgument.FullName != self.ReturnType.FullName) { continue; } } else if (method.ReturnType.FullName != self.ReturnType.FullName) { continue; } for (int i = 0; i < method.Parameters.Count; i++) { TypeReference parameterType = method.Parameters[i].ParameterType; if (parameterType.IsGenericParameter) { int parameterPosition = (parameterType as GenericParameter).Position; TypeReference genericArgument; if (!type.PostionToArgument.TryGetValue(parameterPosition, out genericArgument)) { continue; } if (genericArgument.FullName != self.Parameters[i].ParameterType.FullName) { continue; } } else if (parameterType.FullName != self.Parameters[i].ParameterType.FullName) { continue; } } } return method; } } return null; }
/// <summary> /// Finds the serializer information. /// </summary> /// <param name="type">The type.</param> /// <param name="generic">If set to true, when using <see cref="DataSerializerGenericMode.Type"/>, it will returns the generic version instead of actual type one.</param> /// <returns></returns> /// <exception cref="System.InvalidOperationException">Not sure how to process this inherited serializer</exception> internal SerializableTypeInfo FindSerializerInfo(TypeReference type, bool generic) { if (type == null || type.FullName == typeof(object).FullName || type.FullName == typeof(ValueType).FullName || type.IsGenericParameter) { return(null); } var resolvedType = type.Resolve(); // Nested type if (resolvedType.IsNested) { // Check public/private flags if (!resolvedType.IsNestedPublic && !resolvedType.IsNestedAssembly) { return(null); } } if (resolvedType.IsEnum) { // Enum // Let's generate a EnumSerializer var enumSerializerType = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.EnumSerializer`1"); var serializerType = new GenericInstanceType(enumSerializerType); serializerType.GenericArguments.Add(type); var serializableTypeInfo = new SerializableTypeInfo(serializerType, true, DataSerializerGenericMode.None); AddSerializableType(type, serializableTypeInfo); return(serializableTypeInfo); } // 1. Check if there is a Serializable attribute // Note: Not anymore since we don't want all system types to have unknown complex serializers. //if (((resolvedType.Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable) || resolvedType.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(SerializableAttribute).FullName)) //{ // serializerInfo.Serializable = true; // serializerInfo.ComplexSerializer = true; // serializerInfo.ComplexSerializerName = SerializerTypeName(resolvedType); // return serializerInfo; //} // 2.1. Check if there is DataSerializerAttribute on this type (if yes, it is serializable, but not a "complex type") var dataSerializerAttribute = resolvedType.CustomAttributes.FirstOrDefault( x => x.AttributeType.FullName == "SiliconStudio.Core.Serialization.DataSerializerAttribute"); if (dataSerializerAttribute != null) { var modeField = dataSerializerAttribute.Fields.FirstOrDefault(x => x.Name == "Mode"); var mode = (modeField.Name != null) ? (DataSerializerGenericMode)modeField.Argument.Value : DataSerializerGenericMode.None; // TODO: Replace with ResolveGenericsVisitor var dataSerializerType = ((TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value); if (mode == DataSerializerGenericMode.Type || (mode == DataSerializerGenericMode.TypeAndGenericArguments && type is GenericInstanceType)) { var genericSerializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode) { Inherited = true }; AddSerializableType(type, genericSerializableTypeInfo); var actualSerializerType = new GenericInstanceType(dataSerializerType); // Add Type as generic arguments actualSerializerType.GenericArguments.Add(type); // If necessary, add generic arguments too if (mode == DataSerializerGenericMode.TypeAndGenericArguments) { foreach (var genericArgument in ((GenericInstanceType)type).GenericArguments) { actualSerializerType.GenericArguments.Add(genericArgument); } } // Special case for GenericMode == DataSerializerGenericMode.Type: we store actual serializer instantiation in SerializerType (alongside the generic version in GenericSerializerType). var serializableTypeInfo = new SerializableTypeInfo(actualSerializerType, true); AddSerializableType(type, serializableTypeInfo); if (!generic) { return(serializableTypeInfo); } return(genericSerializableTypeInfo); } else { var serializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode) { Inherited = false }; AddSerializableType(type, serializableTypeInfo); return(serializableTypeInfo); } } // 2.2. Check if SerializableExtendedAttribute is set on this class, or any of its base class with ApplyHierarchy var serializableExtendedAttribute = resolvedType.CustomAttributes.FirstOrDefault( x => x.AttributeType.FullName == "SiliconStudio.Core.DataContractAttribute"); if (dataSerializerAttribute == null && serializableExtendedAttribute != null) { // CHeck if ApplyHierarchy is active, otherwise it needs to be the exact type. var inherited = serializableExtendedAttribute.Properties.Where(x => x.Name == "Inherited") .Select(x => (bool)x.Argument.Value) .FirstOrDefault(); var serializableTypeInfo = CreateComplexSerializer(type); serializableTypeInfo.Inherited = inherited; // Process members ProcessComplexSerializerMembers(type, serializableTypeInfo); return(serializableTypeInfo); } // Check if parent type contains Inherited attribute var parentType = ResolveGenericsVisitor.Process(type, type.Resolve().BaseType); if (parentType != null) { // Generate serializer for parent type var parentSerializableInfoType = GenerateSerializer(parentType.Resolve(), false, generic: true); // If Inherited flag is on, we also generate a serializer for this type if (parentSerializableInfoType != null && parentSerializableInfoType.Inherited) { if (parentSerializableInfoType.ComplexSerializer) { var serializableTypeInfo = CreateComplexSerializer(type); serializableTypeInfo.Inherited = true; // Process members ProcessComplexSerializerMembers(type, serializableTypeInfo); return(serializableTypeInfo); } else if (parentSerializableInfoType.Mode == DataSerializerGenericMode.Type || parentSerializableInfoType.Mode == DataSerializerGenericMode.TypeAndGenericArguments) { // Register generic version var genericSerializableTypeInfo = new SerializableTypeInfo(parentSerializableInfoType.SerializerType, true, parentSerializableInfoType.Mode); AddSerializableType(type, genericSerializableTypeInfo); if (!type.HasGenericParameters) { var actualSerializerType = new GenericInstanceType(parentSerializableInfoType.SerializerType); // Add Type as generic arguments actualSerializerType.GenericArguments.Add(type); // If necessary, add generic arguments too if (parentSerializableInfoType.Mode == DataSerializerGenericMode.TypeAndGenericArguments) { foreach (var genericArgument in ((GenericInstanceType)parentType).GenericArguments) { actualSerializerType.GenericArguments.Add(genericArgument); } } // Register actual type var serializableTypeInfo = new SerializableTypeInfo(actualSerializerType, true); AddSerializableType(type, serializableTypeInfo); if (!generic) { return(serializableTypeInfo); } } return(genericSerializableTypeInfo); } else { throw new InvalidOperationException("Not sure how to process this inherited serializer"); } } } return(null); }
/// <summary> /// Ensure the following type can be serialized. If not, try to register appropriate serializer. /// This method can be recursive. /// </summary> /// <param name="type">The type.</param> public SerializableTypeInfo GenerateSerializer(TypeReference type, bool force = true, string profile = "Default", bool generic = false) { var serializableTypes = GetSerializableTypes(profile); // Already handled? SerializableTypeInfo serializableTypeInfo; if (serializableTypes.TryGetSerializableTypeInfo(type, generic, out serializableTypeInfo)) { return(serializableTypeInfo); } // Try to get one without generic if (generic && serializableTypes.TryGetSerializableTypeInfo(type, false, out serializableTypeInfo)) { return(serializableTypeInfo); } // TDOO: Array, List, Generic types, etc... (equivalent of previous serializer factories) var arrayType = type as ArrayType; if (arrayType != null) { // Only proceed if element type is serializable (and in Default profile, otherwise ElementType is enough) if (GenerateSerializer(arrayType.ElementType, force, profile) != null) { if (profile == "Default") { var arraySerializerType = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ArraySerializer`1"); var serializerType = new GenericInstanceType(arraySerializerType); serializerType.GenericArguments.Add(arrayType.ElementType); AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true), profile); return(serializableTypeInfo); } else { // Fallback to default return(GenerateSerializer(type, force, "Default")); } } return(null); } // Try to match with existing generic serializer (for List, Dictionary, etc...) var genericInstanceType = type as GenericInstanceType; if (genericInstanceType != null) { var elementType = genericInstanceType.ElementType; SerializableTypeInfo elementSerializableTypeInfo; if ((elementSerializableTypeInfo = GenerateSerializer(elementType, false, profile, true)) != null) { switch (elementSerializableTypeInfo.Mode) { case DataSerializerGenericMode.Type: { var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType); serializerType.GenericArguments.Add(type); AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile); break; } case DataSerializerGenericMode.TypeAndGenericArguments: { var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType); serializerType.GenericArguments.Add(type); foreach (var genericArgument in genericInstanceType.GenericArguments) { // Generate serializer for each generic argument //GenerateSerializer(genericArgument); serializerType.GenericArguments.Add(genericArgument); } AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile); break; } case DataSerializerGenericMode.GenericArguments: { var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType); foreach (var genericArgument in genericInstanceType.GenericArguments) { // Generate serializer for each generic argument //GenerateSerializer(genericArgument); serializerType.GenericArguments.Add(genericArgument); } AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile); break; } default: throw new NotImplementedException(); } if (elementSerializableTypeInfo.ComplexSerializer) { ProcessComplexSerializerMembers(type, serializableTypeInfo); } return(serializableTypeInfo); } } // Check complex type definitions if (profile == "Default" && (serializableTypeInfo = FindSerializerInfo(type, generic)) != null) { return(serializableTypeInfo); } // Fallback to default if (profile != "Default") { return(GenerateSerializer(type, force, "Default", generic)); } // Part after that is only if a serializer is absolutely necessary. This is skipped when scanning normal assemblies type that might have nothing to do with serialization. if (!force) { return(null); } // Non instantiable type? (object, interfaces, abstract classes) // Serializer can be null since they will be inherited anyway (handled through MemberSerializer) var resolvedType = type.Resolve(); if (resolvedType.IsAbstract || resolvedType.IsAbstract || resolvedType.FullName == typeof(object).FullName) { AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(null, true), profile); return(serializableTypeInfo); } return(null); }
static MethodDefinition GenerateArraySegmentWriteFunc(TypeReference variable, int recursionCount) { GenericInstanceType genericInstance = (GenericInstanceType)variable; TypeReference elementType = genericInstance.GenericArguments[0]; MethodReference elementWriteFunc = GetWriteFunc(elementType, recursionCount + 1); if (elementWriteFunc == null) { return(null); } string functionName = "_WriteArraySegment_" + elementType.Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new writer for this type MethodDefinition writerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType); writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType))); writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, variable)); writerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); writerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); writerFunc.Body.InitLocals = true; ILProcessor worker = writerFunc.Body.GetILProcessor(); MethodReference countref = Weaver.ArraySegmentCountReference.MakeHostInstanceGeneric(genericInstance); // int length = value.Count; worker.Append(worker.Create(OpCodes.Ldarga_S, (byte)1)); worker.Append(worker.Create(OpCodes.Call, countref)); worker.Append(worker.Create(OpCodes.Stloc_0)); // writer.WritePackedInt32(length); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(Weaver.int32Type))); // Loop through the ArraySegment<T> and call the writer for each element. // generates this: // for (int i=0; i< length; i++) // { // writer.Write(value.Array[i + value.Offset]); // } worker.Append(worker.Create(OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Stloc_1)); Instruction labelHead = worker.Create(OpCodes.Nop); worker.Append(worker.Create(OpCodes.Br, labelHead)); // loop body Instruction labelBody = worker.Create(OpCodes.Nop); worker.Append(labelBody); // writer.Write(value.Array[i + value.Offset]); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldarga_S, (byte)1)); worker.Append(worker.Create(OpCodes.Call, Weaver.ArraySegmentArrayReference.MakeHostInstanceGeneric(genericInstance))); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldarga_S, (byte)1)); worker.Append(worker.Create(OpCodes.Call, Weaver.ArraySegmentOffsetReference.MakeHostInstanceGeneric(genericInstance))); worker.Append(worker.Create(OpCodes.Add)); worker.Append(worker.Create(OpCodes.Ldelema, elementType)); worker.Append(worker.Create(OpCodes.Ldobj, elementType)); worker.Append(worker.Create(OpCodes.Call, elementWriteFunc)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Add)); worker.Append(worker.Create(OpCodes.Stloc_1)); // end for loop worker.Append(labelHead); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Blt, labelBody)); // return worker.Append(worker.Create(OpCodes.Ret)); return(writerFunc); }