/// <summary> /// Given a single item function that should be a static method, this builds a serialized version of /// that method that should be enough to "recover" it, assuming it is a "recoverable" method (recoverable /// here is a loose definition, meaning that <see cref="DeserializeStaticDelegateOrNull"/> is capable /// of creating it, which includes among other things that it's static, non-lambda, accessible to /// this assembly, etc.). /// </summary> /// <param name="func">The method that should be "recoverable"</param> /// <returns>A string array describing the input method</returns> public static byte[] GetSerializedStaticDelegate(ExtLambdaTransform.LoadDelegate func) { Contracts.CheckValue(func, nameof(func)); Contracts.CheckParam(func.Target == null, nameof(func), "The load delegate must be static"); Contracts.CheckParam(Utils.Size(func.GetInvocationList()) <= 1, nameof(func), "The load delegate must not be a multicast delegate"); var meth = func.GetMethodInfo(); using (var ms = new MemoryStream()) { var formatter = new BinaryFormatter(); #if CORECLR var m = new CoreHackMethodInfo(); m.AssemblyName = meth.Module.Assembly.FullName; m.MethodName = meth.Name; m.ClassName = meth.DeclaringType.ToString(); formatter.Serialize(ms, m); #else formatter.Serialize(ms, meth); #endif var result = ms.ToArray(); // I assume it must be impossible to serialize in 0 bytes. Contracts.Assert(Utils.Size(result) > 0); return(result); } }
/// <summary> /// Create a filter transform that is savable iff <paramref name="saveAction"/> and <paramref name="loadFunc"/> are /// not null. /// </summary> /// <param name="env">The host environment</param> /// <param name="source">The dataview upon which we construct the transform</param> /// <param name="filterFunc">The function by which we transform source to destination columns and decide whether /// to keep the row.</param> /// <param name="initStateAction">The function that is called once per cursor to initialize state. Can be null.</param> /// <param name="saveAction">An action that allows us to save state to the serialization stream. May be /// null simultaneously with <paramref name="loadFunc"/>.</param> /// <param name="loadFunc">A function that given the serialization stream and a data view, returns /// an <see cref="ITransformTemplate"/>. The intent is, this returned object should itself be a /// <see cref="CustomMappingTransformer{TSrc,TDst}"/>, but this is not strictly necessary. This delegate should be /// a static non-lambda method that this assembly can legally call. May be null simultaneously with /// <paramref name="saveAction"/>.</param> /// <param name="inputSchemaDefinition">The schema definition overrides for <typeparamref name="TSrc"/></param> /// <param name="outputSchemaDefinition">The schema definition overrides for <typeparamref name="TDst"/></param> public ExtStatefulFilterTransform(IHostEnvironment env, IDataView source, Func <TSrc, TDst, TState, bool> filterFunc, Action <TState> initStateAction, Action <BinaryWriter> saveAction, ExtLambdaTransform.LoadDelegate loadFunc, SchemaDefinition inputSchemaDefinition = null, SchemaDefinition outputSchemaDefinition = null) : base(env, RegistrationName, saveAction, loadFunc) { Host.AssertValue(source, "source"); Host.AssertValue(filterFunc, "filterFunc"); Host.AssertValueOrNull(initStateAction); Host.AssertValueOrNull(inputSchemaDefinition); Host.AssertValueOrNull(outputSchemaDefinition); _source = source; _filterFunc = filterFunc; _initStateAction = initStateAction; _inputSchemaDefinition = inputSchemaDefinition; _typedSource = TypedCursorable <TSrc> .Create(Host, Source, false, inputSchemaDefinition); var outSchema = InternalSchemaDefinition.Create(typeof(TDst), outputSchemaDefinition); _addedSchema = outSchema; _bindings = new ColumnBindings(Source.Schema, DataViewConstructionUtils.GetSchemaColumns(outSchema)); }
protected ExtLambdaTransformBase(IHostEnvironment env, string name, Action <BinaryWriter> saveAction, ExtLambdaTransform.LoadDelegate loadFunc) { Contracts.AssertValue(env); env.AssertNonWhiteSpace(name); Host = env.Register(name); Host.Assert((saveAction == null) == (loadFunc == null)); if (saveAction != null) { _saveAction = saveAction; // First, verify as best we can, that we can recover the function, by attempting to do it once. _loadFuncBytes = SerializableExtLambdaTransform.GetSerializedStaticDelegate(loadFunc); Exception error; var recoveredLoadFunc = SerializableExtLambdaTransform.DeserializeStaticDelegateOrNull(Host, _loadFuncBytes, out error); if (recoveredLoadFunc == null) { Host.AssertValue(error); throw Host.Except(error, "Load function does not appear recoverable"); } } AssertConsistentSerializable(); }