public SafeCast(Operand op, Type t) { _op = op; _t = t; if (t.IsValueType) _conditional = _op.Is(_t).Conditional(_op.Cast(_t), new DefaultValue(_t)); }
public SafeCast(Operand op, Type t) { _op = op; _t = t; if (t.IsValueType) { _conditional = _op.Is(_t).Conditional(_op.Cast(_t), new DefaultValue(_t)); } }
// example based on the MSDN Versioning Sample (versioning.cs) public static void GenVersioning(AssemblyGen ag) { TypeGen MyBase = ag.Public.Class("MyBase"); { MyBase.Public.Virtual.Method <string>("Meth1").GetCode() .Return("MyBase-Meth1"); MyBase.Public.Virtual.Method <string>("Meth2").GetCode() .Return("MyBase-Meth2"); MyBase.Public.Virtual.Method <string>("Meth3").GetCode() .Return("MyBase-Meth3"); } TypeGen MyDerived = ag.Class("MyDerived", MyBase); { // Overrides the virtual method Meth1 using the override keyword: MyDerived.Public.Override.Method <string>("Meth1").GetCode() .Return("MyDerived-Meth1"); // Explicitly hide the virtual method Meth2 using the new // keyword: // remark: new is not supported/required in RunSharp MyDerived.Public.Method <string>("Meth2").GetCode() .Return("MyDerived-Meth2"); // Because no keyword is specified in the following declaration // a warning will be issued to alert the programmer that // the method hides the inherited member MyBase.Meth3(): // remark: this warning is not supported in RunSharp MyDerived.Public.Method <string>("Meth3").GetCode() .Return("MyDerived-Meth3"); CodeGen g = MyDerived.Public.Static.Void("Main"); { Operand mD = g.Local(Exp.New(MyDerived)); Operand mB = g.Local(mD.Cast(MyBase)); g.WriteLine(mB.Invoke("Meth1")); g.WriteLine(mB.Invoke("Meth2")); g.WriteLine(mB.Invoke("Meth3")); } } }
public void CreateAssembly(string p1, string p2) { AssemblyGen ag = new AssemblyGen(_path + @"\DemoHost.exe"); Assembly asm = Assembly.LoadFrom(_path + @"\WaveTech.Scutex.Licensing.dll"); ag.Attribute(asm.GetType("WaveTech.Scutex.Model.LicenseAttribute"), p1, p2); TypeGen DemoHost = ag.Public.Class("DemoHost"); { CodeGen g = DemoHost.Public.Static.Method(typeof(void), "Main"); { g.WriteLine("===================================================="); g.WriteLine("| SCUTEX |"); g.WriteLine("| DEMO HOST FOR TRIAL DIALOG TESTING |"); g.WriteLine("===================================================="); g.WriteLine(""); g.WriteLine(""); g.WriteLine("Your trial dialog or form should display in a few seconds..."); Operand licensingManager = g.Local(Exp.New(asm.GetType("WaveTech.Scutex.Licensing.LicensingManager"))); Operand value = g.Local(asm.GetType("WaveTech.Scutex.Model.InteractionModes")); Operand value2 = g.Local(typeof(System.Int32)); g.Assign(value2, 1); g.Assign(value, value2.Cast(asm.GetType("WaveTech.Scutex.Model.InteractionModes"))); Operand scutexLicensing = g.Local(asm.GetType("WaveTech.Scutex.Model.ScutexLicense")); g.Assign(scutexLicensing, licensingManager.Invoke("Validate", value)); g.Return(); } } ag.Save(); asm = null; }
// example based on the MSDN User-Defined Conversions Sample (structconversion.cs) public static void GenStructConversion(AssemblyGen ag) { TypeGen BinaryNumeral = ag.Struct("BinaryNumeral"); { FieldGen value = BinaryNumeral.Private.Field <int>("value"); CodeGen g = BinaryNumeral.Public.Constructor().Parameter <int>("value"); { g.Assign(value, g.Arg("value")); } g = BinaryNumeral.Public.ImplicitConversionFrom <int>(); { g.Return(Exp.New(BinaryNumeral, g.Arg("value"))); } g = BinaryNumeral.Public.ImplicitConversionTo <string>(); { g.Return("Conversion not yet implemented"); } g = BinaryNumeral.Public.ExplicitConversionTo <int>("binary"); { g.Return(g.Arg("binary").Field("value")); } } TypeGen RomanNumeral = ag.Struct("RomanNumeral"); { FieldGen value = RomanNumeral.Private.Field <int>("value"); CodeGen g = RomanNumeral.Public.Constructor().Parameter <int>("value"); { g.Assign(value, g.Arg("value")); } g = RomanNumeral.Public.ImplicitConversionFrom <int>(); { g.Return(Exp.New(RomanNumeral, g.Arg("value"))); } g = RomanNumeral.Public.ImplicitConversionFrom(BinaryNumeral, "binary"); { g.Return(Exp.New(RomanNumeral, g.Arg("binary").Cast <int>())); } g = RomanNumeral.Public.ExplicitConversionTo <int>("roman"); { g.Return(g.Arg("roman").Field("value")); } g = RomanNumeral.Public.ImplicitConversionTo <string>(); { g.Return("Conversion not yet implemented"); } } TypeGen Test = ag.Class("Test"); { CodeGen g = Test.Public.Static.Void("Main"); { Operand roman = g.Local(RomanNumeral); g.Assign(roman, 10); Operand binary = g.Local(BinaryNumeral); // Perform a conversion from a RomanNumeral to a // BinaryNumeral: g.Assign(binary, roman.Cast <int>().Cast(BinaryNumeral)); // Performs a conversion from a BinaryNumeral to a RomanNumeral. // No cast is required: g.Assign(roman, binary); g.WriteLine(binary.Cast <int>()); g.WriteLine(binary); } } }
// example based on the MSDN User-Defined Conversions Sample (conversion.cs) public static void GenConversion(AssemblyGen ag) { TypeGen RomanNumeral = ag.Struct("RomanNumeral"); { FieldGen value = RomanNumeral.Private.Field <int>("value"); CodeGen g = RomanNumeral.Public.Constructor().Parameter <int>("value"); { g.Assign(value, g.Arg("value")); } // Declare a conversion from an int to a RomanNumeral. Note the // the use of the operator keyword. This is a conversion // operator named RomanNumeral: g = RomanNumeral.Public.ImplicitConversionFrom <int>(); { // Note that because RomanNumeral is declared as a struct, // calling new on the struct merely calls the constructor // rather than allocating an object on the heap: g.Return(Exp.New(RomanNumeral, g.Arg("value"))); } // Declare an explicit conversion from a RomanNumeral to an int: g = RomanNumeral.Public.ExplicitConversionTo <int>("roman"); { g.Return(g.Arg("roman").Field("value")); } // Declare an implicit conversion from a RomanNumeral to // a string: g = RomanNumeral.Public.ImplicitConversionTo <string>(); { g.Return("Conversion not yet implemented"); } } TypeGen Test = ag.Class("Test"); { CodeGen g = Test.Public.Static.Void("Main"); { Operand numeral = g.Local(RomanNumeral); g.Assign(numeral, 10); // Call the explicit conversion from numeral to int. Because it is // an explicit conversion, a cast must be used: g.WriteLine(numeral.Cast <int>()); // Call the implicit conversion to string. Because there is no // cast, the implicit conversion to string is the only // conversion that is considered: g.WriteLine(numeral); // Call the explicit conversion from numeral to int and // then the explicit conversion from int to short: Operand s = g.Local(numeral.Cast <short>()); g.WriteLine(s); } } }
// example based on the MSDN Explicit Interface Implementation Sample (explicit.cs) public static void GenExplicit2(AssemblyGen ag) { // Declare the English units interface: TypeGen IEnglishDimensions = ag.Interface("IEnglishDimensions"); { IEnglishDimensions.Method(typeof(float), "Length"); IEnglishDimensions.Method(typeof(float), "Width"); } // Declare the metric units interface: TypeGen IMetricDimensions = ag.Interface("IMetricDimensions"); { IMetricDimensions.Method(typeof(float), "Length"); IMetricDimensions.Method(typeof(float), "Width"); } // Declare the "Box" class that implements the two interfaces: // IEnglishDimensions and IMetricDimensions: TypeGen Box = ag.Class("Box", typeof(object), IEnglishDimensions, IMetricDimensions); { FieldGen lengthInches = Box.Field(typeof(float), "lengthInches"); FieldGen widthInches = Box.Field(typeof(float), "widthInches"); CodeGen g = Box.Public.Constructor() .Parameter(typeof(float), "length") .Parameter(typeof(float), "width") ; { g.Assign(lengthInches, g.Arg("length")); g.Assign(widthInches, g.Arg("width")); } // Explicitly implement the members of IEnglishDimensions: g = Box.MethodImplementation(IEnglishDimensions, typeof(float), "Length"); { g.Return(lengthInches); } g = Box.MethodImplementation(IEnglishDimensions, typeof(float), "Width"); { g.Return(widthInches); } // Explicitly implement the members of IMetricDimensions: g = Box.MethodImplementation(IMetricDimensions, typeof(float), "Length"); { g.Return(lengthInches * 2.54f); } g = Box.MethodImplementation(IMetricDimensions, typeof(float), "Width"); { g.Return(widthInches * 2.54f); } g = Box.Public.Static.Method(typeof(void), "Main"); { // Declare a class instance "myBox": Operand myBox = g.Local(Exp.New(Box, 30.0f, 20.0f)); // Declare an instance of the English units interface: Operand eDimensions = g.Local(myBox.Cast(IEnglishDimensions)); // Declare an instance of the metric units interface: Operand mDimensions = g.Local(myBox.Cast(IMetricDimensions)); // Print dimensions in English units: g.WriteLine("Length(in): {0}", eDimensions.Invoke("Length")); g.WriteLine("Width (in): {0}", eDimensions.Invoke("Width")); // Print dimensions in metric units: g.WriteLine("Length(cm): {0}", mDimensions.Invoke("Length")); g.WriteLine("Width (cm): {0}", mDimensions.Invoke("Width")); } } }
/// <summary> /// Create a wrapper class for a generic interface with more general type parameters than the wrapped interface. /// Downcasts to the correct more specific type are generated where necessary. /// This of course breaks type safety, and only calls to the class with the correct orginal types will work. /// Incorrect calls will throw <see cref = "InvalidCastException" />. /// </summary> /// <remarks> /// This is useful during reflection, when you don't want to know about specific types, but you can guarantee /// that a certain call will always be done with objects of the correct type. /// TODO: This non-generic method is only needed since RunSharp can't call generic methods, needed to generate wrappers recursively. /// TODO: Possibly Castle DynamicProxy could replace this if it allows creating 'non-matching' proxies and thus support the downcasting. /// </remarks> /// <param name = "typeToCreate">The less-specific generic type of the wrapper which will be generated.</param> /// <param name = "o">The object to wrap, which should implement the desired interface, with arbitrary type parameters.</param> /// <returns>An instance of the specified type which wraps the given object.</returns> public static object CreateGenericInterfaceWrapper(Type typeToCreate, object o) { Contract.Requires(o.GetType().IsOfGenericType(typeToCreate.GetGenericTypeDefinition())); Contract.Requires(typeToCreate.IsInterface); Type typeToCreateGeneric = typeToCreate.GetGenericTypeDefinition(); Type innerType = o.GetType(); Type innerMatchingType = innerType.GetMatchingGenericType(typeToCreateGeneric); // Implement passed type and redirect all public calls to inner instance. var assembly = new AssemblyGen("Whathecode.System.RunSharp"); TypeGen type = assembly.Public.Class("Wrapped" + typeToCreate.Name, typeof(object), typeToCreate); { const string inner = "inner"; FieldGen innerInstance = type.Private.Field(innerType, "_innerInstance"); FieldGen returnCached = type.Private.Field(typeof(Dictionary <int, object>), "_returnCached"); FieldGen returnWrappers = type.Private.Field(typeof(Dictionary <int, object>), "_returnWrappers"); // Create constructor which takes the wrapped instance as an argument. ConstructorGen constructor = type.Public.Constructor(); { constructor.Parameter(innerType, inner); CodeGen code = constructor.GetCode(); { code.Assign(innerInstance, code.Arg(inner)); code.Assign(returnCached, Exp.New(typeof(Dictionary <int, object>))); code.Assign(returnWrappers, Exp.New(typeof(Dictionary <int, object>))); } } // Create methods. int methodCount = 0; MethodInfo[] innerMethods = innerMatchingType.GetFlattenedInterfaceMethods(ReflectionHelper.FlattenedInstanceMembers).ToArray(); MethodInfo[] toCreateMethods = typeToCreate.GetFlattenedInterfaceMethods(ReflectionHelper.FlattenedInstanceMembers).ToArray(); MethodInfo[] genericMethods = typeToCreateGeneric.GetFlattenedInterfaceMethods(ReflectionHelper.FlattenedInstanceMembers).ToArray(); foreach (var method in innerMethods .Zip(toCreateMethods, genericMethods, (matching, toCreate, generic) => new { Id = methodCount++, Matching = matching, ToCreate = toCreate, Generic = generic }) .Where(z => z.Matching.IsPublic || z.Matching.IsFamily)) { // TODO: Not quite certain why override is required for extended interfaces (DeclaringType != typeTocreate), // but this seems to work. MethodInfo toCreate = method.ToCreate; MethodGen methodGen = toCreate.DeclaringType == typeToCreate ? type.MethodImplementation(typeToCreate, toCreate.ReturnType, toCreate.Name) : type.Public.Override.Method(toCreate.ReturnType, toCreate.Name); { ParameterInfo[] toCreateParameters = toCreate.GetParameters(); var parameters = toCreateParameters .Select(p => { var info = methodGen.BeginParameter(p.ParameterType, p.Name); info.End(); return(info); }).ToArray(); CodeGen code = methodGen.GetCode(); { // Cast arguments to the type of the inner instance. Operand[] args = parameters.Select(p => code.Arg(p.Name)).ToArray(); Operand[] castArgs = { }; if (args.Length > 0) { Type[] parameterTypes = method.Matching.GetParameters().Select(p => p.ParameterType).ToArray(); // TODO: When searching for generic methods, GetMethod returns null. http://stackoverflow.com/questions/4035719/getmethod-for-generic-method // Even when the correct method is found through custom filtering, RunSharp does not seem to be able to create generic methods yet. MethodInfo methodToCall = innerType.GetMethod(toCreate.Name, ReflectionHelper.FlattenedInstanceMembers, parameterTypes); castArgs = methodToCall.GetParameters() .Select((p, index) => args[index].Cast(typeof(object)).Cast(p.ParameterType)).ToArray(); } // Call inner instance and return value when needed. if (toCreate.ReturnType != typeof(void)) { Operand result = innerInstance.Invoke(toCreate.Name, castArgs); // Wrappers will recursively need to be created for generic return types. Type genericReturnType = method.Generic.ReturnType; if (genericReturnType.IsGenericType && genericReturnType.ContainsGenericParameters && genericReturnType.IsInterface) { // Check whether a new result is returned. Operand innerCached = code.Local(typeof(object)); code.If(returnCached.Invoke("TryGetValue", method.Id, innerCached.Ref())); { code.If((innerCached == result).LogicalNot()); { code.Invoke(returnWrappers, "Remove", method.Id); code.Invoke(returnCached, "Remove", method.Id); code.Invoke(returnCached, "Add", method.Id, result); } code.End(); } code.Else(); { code.Invoke(returnCached, "Add", method.Id, result); } code.End(); // Check whether a wrapper needs to be generated. Operand wrappedCached = code.Local(typeof(object)); code.If(returnWrappers.Invoke("TryGetValue", method.Id, wrappedCached.Ref()).LogicalNot()); { Operand proxied = Static.Invoke(typeof(Proxy), "CreateGenericInterfaceWrapper", toCreate.ReturnType, result); code.Assign(wrappedCached, proxied); code.Invoke(returnWrappers, "Add", method.Id, wrappedCached); } code.End(); code.Return(wrappedCached.Cast(toCreate.ReturnType)); } else { // A simple cast will work. // TODO: Throw proper exception when this is known to fail. E.g. generic type which is not an interface? code.Return(result.Cast(toCreate.ReturnType)); } } else { code.Invoke(innerInstance, toCreate.Name, castArgs); } } } } } Type wrapperType = type.GetCompletedType(true); return(Activator.CreateInstance(wrapperType, new[] { o })); }
protected override void EmitRead(AqlaSerializer.Compiler.CompilerContext ctx, AqlaSerializer.Compiler.Local valueFrom) { var g = ctx.G; using (ctx.StartDebugBlockAuto(this)) using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) using (Compiler.Local oldValueForSubTypeHelpers = ctx.Local(value.Type)) using (Compiler.Local createdNew = ctx.Local(typeof(bool), true)) { bool asList = IsList && !SuppressIList; // can't call clear? => create new! bool forceNewInstance = !AppendToCollection && !asList; ListHelpers.EmitRead( ctx.G, (onSuccess, onFail) => { using (ctx.StartDebugBlockAuto(this, "readNextMeta")) { if (_metaType != null) { g.If(g.ReaderFunc.TryReadFieldHeader_bool(ListHelpers.FieldSubtype)); { using (ctx.StartDebugBlockAuto(this, "subtype handler")) { g.Assign(oldValueForSubTypeHelpers, forceNewInstance ? null : value.AsOperand); _subTypeHelpers.EmitTryRead( g, oldValueForSubTypeHelpers, _metaType, r => { using (ctx.StartDebugBlockAuto(this, "subtype handler - read")) { if (r != null) { ctx.MarkDebug("// creating list subtype"); r.Serializer.EmitCreateInstance(ctx); ctx.StoreValue(value); g.Assign(createdNew, true); } } }); } onSuccess(); } g.Else(); { onFail(); } g.End(); } else { onFail(); } } } , () => { using (ctx.StartDebugBlockAuto(this, "prepareInstance")) { var createInstanceCondition = value.AsOperand == null; // also create new if should clear existing instance on not lists if (forceNewInstance) { createInstanceCondition = createInstanceCondition || !createdNew.AsOperand; } g.If(createInstanceCondition); { ctx.MarkDebug("// creating new list"); EmitCreateInstance(ctx); ctx.StoreValue(value); g.Reader.NoteObject(value); } g.Else(); { g.If(!createdNew.AsOperand); { g.Reader.NoteObject(value); if (asList && !AppendToCollection) { ctx.MarkDebug("// clearing existing list"); // ReSharper disable once PossibleNullReferenceException g.Invoke(value, "Clear"); } } g.End(); } g.End(); } }, v => { // TODO do null checks without allowing user == operators! using (ctx.StartDebugBlockAuto(this, "add")) { #if DEBUG_COMPILE_2 g.If(v.AsOperand != null); { g.ctx.MarkDebug("adding " + v.AsOperand.InvokeToString()); } g.End(); #endif if (asList) { ctx.MarkDebug("// using Add method"); Operand instance = value; if (_add != null && !Helpers.IsAssignableFrom(_add.DeclaringType, ExpectedType)) { instance = instance.Cast(_add.DeclaringType); // TODO optimize to local } g.Invoke(instance, "Add", v); } else { ctx.MarkDebug("// using add delegate"); ctx.LoadAddress(value, ExpectedType); if (!Helpers.IsAssignableFrom(_add.DeclaringType, ExpectedType)) { ctx.Cast(_add.DeclaringType); } ctx.LoadValue(v); ctx.EmitCall(this._add); } } } ); if (EmitReadReturnsValue) { ctx.MarkDebug("returning list"); ctx.LoadValue(value); } } }