- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
已经有很多关于这个的帖子,都试图序列化一个 Func 委托(delegate)。
但是当委托(delegate)的使用总是很明确时,有人能想到一个替代方案吗?
我们有一个通用的创建命令,它将委托(delegate)作为构造函数中的参数。此委托(delegate)将为创建命令创建项目:
public class CreateCommand<T> : Command
{
public T Item;
protected Func<T> Constructor;
public ClientCreateCommand(Func<T> constructor)
{
Constructor = constructor;
}
public override void Execute()
{
Item = Constructor();
}
}
命令是这样使用的:
var c = new CreateCommand<MyType>( () => Factory.CreateMyType(param1, param2, ...) );
History.Insert(c);
然后 History 序列化命令并将其发送到服务器。 ofc 委托(delegate)不能按原样序列化,我们得到一个异常。
现在有人能想出一个非常简单的 Constructor 类,它可以序列化并完成与 lambda 表达式相同的工作吗?意味着它需要一个参数列表并返回一个类型 T 的实例,然后我们可以这样写:
var constructor = new Constructor<MyType>(param1, param2, ...);
var c = new CreateCommand<MyType>(constructor);
History.Insert(c);
Constructor 类会是什么样子?感谢您的任何想法!
最佳答案
编辑(2):我提供了几个完整的示例实现。它们在下面分类为“实现 1”和“实现 2”。
您的委托(delegate)本质上是一个工厂。您可以定义一个工厂接口(interface)并创建一个类来为您的 Item 类实现该接口(interface)。下面是一个例子:
public interface IFactory<T>
{
T Create();
}
[Serializable]
public class ExampleItemFactory : IFactory<T>
{
public int Param1 { get; set; }
public string Param2 { get; set; }
#region IFactory<T> Members
public Item Create()
{
return new Item(this.Param1, this.Param2);
}
#endregion
}
public class CreateCommand<T> : Command
{
public T Item;
protected IFactory<T> _ItemFactory;
public CreateCommand(IFactory<T> factory)
{
_ItemFactory = factory;
}
public override void Execute()
{
Item = _ItemFactory.Create();
}
}
您将按以下方式使用此代码:
IFactory<Item> itemFactory = new ExampleItemFactory { Param1 = 5, Param2 = "Example!" };
CreateCommand<Item> command = new CreateCommand<Item>(itemFactory);
command.Execute();
编辑(1):IFactory<T>
的具体实现您的应用程序需求将取决于您。您可以为每个需要的类创建特定的工厂类,或者您可以创建某种动态创建实例的工厂,例如使用 Activator.CreateInstance 函数或可能使用某种控制反转框架,例如 Spring 或结构图。
下面是一个使用两个工厂实现的完整示例实现。一个实现可以使用该类型的构造函数和匹配的参数来创建给定参数数组的任何类型。另一个实现创建已在我的“工厂”类中注册的任何类型。
Debug.Assert 语句确保一切都按预期运行。我运行这个应用程序没有错误。
[Serializable]
public abstract class Command
{
public abstract void Execute();
}
public class Factory
{
static Dictionary<Type, Func<object[], object>> _DelegateCache = new Dictionary<Type, Func<object[], object>>();
public static void Register<T>(Func<object[], object> @delegate)
{
_DelegateCache[typeof(T)] = @delegate;
}
public static T CreateMyType<T>(params object[] args)
{
return (T)_DelegateCache[typeof(T)](args);
}
}
public interface IFactory<T>
{
T Create();
}
[Serializable]
public class CreateCommand<T> : Command
{
public T Item { get; protected set; }
protected IFactory<T> _ItemFactory;
public CreateCommand(IFactory<T> itemFactory)
{
this._ItemFactory = itemFactory;
}
public override void Execute()
{
this.Item = this._ItemFactory.Create();
}
}
// This class is a base class that represents a factory capable of creating an instance using a dynamic set of arguments.
[Serializable]
public abstract class DynamicFactory<T> : IFactory<T>
{
public object[] Args { get; protected set; }
public DynamicFactory(params object[] args)
{
this.Args = args;
}
public DynamicFactory(int numberOfArgs)
{
if (numberOfArgs < 0)
throw new ArgumentOutOfRangeException("numberOfArgs", "The numberOfArgs parameter must be greater than or equal to zero.");
this.Args = new object[numberOfArgs];
}
#region IFactory<T> Members
public abstract T Create();
#endregion
}
// This implementation uses the Activator.CreateInstance function to create an instance
[Serializable]
public class DynamicConstructorFactory<T> : DynamicFactory<T>
{
public DynamicConstructorFactory(params object[] args) : base(args) { }
public DynamicConstructorFactory(int numberOfArgs) : base(numberOfArgs) { }
public override T Create()
{
return (T)Activator.CreateInstance(typeof(T), this.Args);
}
}
// This implementation uses the Factory.CreateMyType function to create an instance
[Serializable]
public class MyTypeFactory<T> : DynamicFactory<T>
{
public MyTypeFactory(params object[] args) : base(args) { }
public MyTypeFactory(int numberOfArgs) : base(numberOfArgs) { }
public override T Create()
{
return Factory.CreateMyType<T>(this.Args);
}
}
[Serializable]
class DefaultConstructorExample
{
public DefaultConstructorExample()
{
}
}
[Serializable]
class NoDefaultConstructorExample
{
public NoDefaultConstructorExample(int a, string b, float c)
{
}
}
[Serializable]
class PrivateConstructorExample
{
private int _A;
private string _B;
private float _C;
private PrivateConstructorExample()
{
}
public static void Register()
{
// register a delegate with the Factory class that will construct an instance of this class using an array of arguments
Factory.Register<PrivateConstructorExample>((args) =>
{
if (args == null || args.Length != 3)
throw new ArgumentException("Expected 3 arguments.", "args");
if (!(args[0] is int))
throw new ArgumentException("First argument must be of type System.Int32.", "args[0]");
if (!(args[1] is string))
throw new ArgumentException("Second argument must be of type System.String.", "args[1]");
if (!(args[2] is float))
throw new ArgumentException("Third argument must be of type System.Single.", "args[2]");
var instance = new PrivateConstructorExample();
instance._A = (int)args[0];
instance._B = (string)args[1];
instance._C = (float)args[2];
return instance;
});
}
}
class Program
{
static void Main(string[] args)
{
var factory1 = new DynamicConstructorFactory<DefaultConstructorExample>(null);
var command1 = new CreateCommand<DefaultConstructorExample>(factory1);
var factory2 = new DynamicConstructorFactory<NoDefaultConstructorExample>(3);
factory2.Args[0] = 5;
factory2.Args[1] = "ABC";
factory2.Args[2] = 7.1f;
var command2 = new CreateCommand<NoDefaultConstructorExample>(factory2);
PrivateConstructorExample.Register(); // register this class so that it can be created by the Factory.CreateMyType function
var factory3 = new MyTypeFactory<PrivateConstructorExample>(3);
factory3.Args[0] = 5;
factory3.Args[1] = "ABC";
factory3.Args[2] = 7.1f;
var command3 = new CreateCommand<PrivateConstructorExample>(factory3);
VerifySerializability<DefaultConstructorExample>(command1);
VerifySerializability<NoDefaultConstructorExample>(command2);
VerifySerializability<PrivateConstructorExample>(command3);
}
static void VerifySerializability<T>(CreateCommand<T> originalCommand)
{
var serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var stream = new System.IO.MemoryStream())
{
System.Diagnostics.Debug.Assert(originalCommand.Item == null); // assert that originalCommand does not yet have a value for Item
serializer.Serialize(stream, originalCommand); // serialize the originalCommand object
stream.Seek(0, System.IO.SeekOrigin.Begin); // reset the stream position to the beginning for deserialization
// deserialize
var deserializedCommand = serializer.Deserialize(stream) as CreateCommand<T>;
System.Diagnostics.Debug.Assert(deserializedCommand.Item == null); // assert that deserializedCommand still does not have a value for Item
deserializedCommand.Execute();
System.Diagnostics.Debug.Assert(deserializedCommand.Item != null); // assert that deserializedCommand now has a value for Item
}
}
}
编辑(2):重读问题后,我想我对提问者真正想表达的意思有了更好的了解。本质上,我们仍然希望利用 lambda 表达式/匿名委托(delegate)提供的灵 active ,但要避免序列化问题。
下面是另一个使用 Factory<T>
的示例实现存储用于返回类型 T 实例的委托(delegate)的类。
[Serializable]
public abstract class Command
{
public abstract void Execute();
}
[Serializable]
public abstract class CreateCommand<T> : Command
{
public T Item { get; protected set; }
}
public class Factory<T>
{
private static readonly object _SyncLock = new object();
private static Func<T> _CreateFunc;
private static Dictionary<string, Func<T>> _CreateFuncDictionary;
/// <summary>
/// Registers a default Create Func delegate for type <typeparamref name="T"/>.
/// </summary>
public static void Register(Func<T> createFunc)
{
lock (_SyncLock)
{
_CreateFunc = createFunc;
}
}
public static T Create()
{
lock (_SyncLock)
{
if(_CreateFunc == null)
throw new InvalidOperationException(string.Format("A [{0}] delegate must be registered as the default delegate for type [{1}]..", typeof(Func<T>).FullName, typeof(T).FullName));
return _CreateFunc();
}
}
/// <summary>
/// Registers a Create Func delegate for type <typeparamref name="T"/> using the given key.
/// </summary>
/// <param name="key"></param>
/// <param name="createFunc"></param>
public static void Register(string key, Func<T> createFunc)
{
lock (_SyncLock)
{
if (_CreateFuncDictionary == null)
_CreateFuncDictionary = new Dictionary<string, Func<T>>();
_CreateFuncDictionary[key] = createFunc;
}
}
public static T Create(string key)
{
lock (_SyncLock)
{
Func<T> createFunc;
if (_CreateFuncDictionary != null && _CreateFuncDictionary.TryGetValue(key, out createFunc))
return createFunc();
else
throw new InvalidOperationException(string.Format("A [{0}] delegate must be registered with the given key \"{1}\".", typeof(Func<T>).FullName, key));
}
}
}
[Serializable]
public class CreateCommandWithDefaultDelegate<T> : CreateCommand<T>
{
public override void Execute()
{
this.Item = Factory<T>.Create();
}
}
[Serializable]
public class CreateCommandWithKeyedDelegate<T> : CreateCommand<T>
{
public string CreateKey { get; set; }
public CreateCommandWithKeyedDelegate(string createKey)
{
this.CreateKey = createKey;
}
public override void Execute()
{
this.Item = Factory<T>.Create(this.CreateKey);
}
}
[Serializable]
class DefaultConstructorExample
{
public DefaultConstructorExample()
{
}
}
[Serializable]
class NoDefaultConstructorExample
{
public NoDefaultConstructorExample(int a, string b, float c)
{
}
}
[Serializable]
class PublicPropertiesExample
{
public int A { get; set; }
public string B { get; set; }
public float C { get; set; }
}
class Program
{
static void Main(string[] args)
{
// register delegates for each type
Factory<DefaultConstructorExample>.Register(() => new DefaultConstructorExample());
Factory<NoDefaultConstructorExample>.Register(() => new NoDefaultConstructorExample(5, "ABC", 7.1f));
Factory<PublicPropertiesExample>.Register(() => new PublicPropertiesExample() { A = 5, B = "ABC", C = 7.1f });
// create commands
var command1 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
var command2 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
var command3 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
// verify that each command can be serialized/deserialized and that the creation logic works
VerifySerializability<DefaultConstructorExample>(command1);
VerifySerializability<DefaultConstructorExample>(command2);
VerifySerializability<DefaultConstructorExample>(command3);
// register additional delegates for each type, distinguished by key
Factory<DefaultConstructorExample>.Register("CreateCommand", () => new DefaultConstructorExample());
Factory<NoDefaultConstructorExample>.Register("CreateCommand", () => new NoDefaultConstructorExample(5, "ABC", 7.1f));
Factory<PublicPropertiesExample>.Register("CreateCommand", () => new PublicPropertiesExample() { A = 5, B = "ABC", C = 7.1f });
// create commands, passing in the create key to the constructor
var command4 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
var command5 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
var command6 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
// verify that each command can be serialized/deserialized and that the creation logic works
VerifySerializability<DefaultConstructorExample>(command4);
VerifySerializability<DefaultConstructorExample>(command5);
VerifySerializability<DefaultConstructorExample>(command6);
}
static void VerifySerializability<T>(CreateCommand<T> originalCommand)
{
var serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var stream = new System.IO.MemoryStream())
{
System.Diagnostics.Debug.Assert(originalCommand.Item == null); // assert that originalCommand does not yet have a value for Item
serializer.Serialize(stream, originalCommand); // serialize the originalCommand object
stream.Seek(0, System.IO.SeekOrigin.Begin); // reset the stream position to the beginning for deserialization
// deserialize
var deserializedCommand = serializer.Deserialize(stream) as CreateCommand<T>;
System.Diagnostics.Debug.Assert(deserializedCommand.Item == null); // assert that deserializedCommand still does not have a value for Item
deserializedCommand.Execute();
System.Diagnostics.Debug.Assert(deserializedCommand.Item != null); // assert that deserializedCommand now has a value for Item
}
}
}
关于c# - 创建可序列化匿名委托(delegate)的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3292191/
我应该编写一个函数来打印一组给定的三个数字中两个较大数字的平方和。 我对这种情况的处理相当笨拙。我没有编写返回一组 3 中最大的两个数字的函数,而是编写了函数,以便表达式减少到两个所需的数字。 # S
如果有人可以提供帮助,我将不胜感激。我一直在敲我的头一天试图让这个工作。我已经在互联网上搜索并重新阅读了手册,但我就是不明白。 guile << __EOF__ ( define heading-li
目前我正在处理一个方案问题,其中我们正在使用方案列表表示一个图。我们使用的第一个变体是表示为 的边列表图 '((x y) (y z) (x z)) 我们正在使用的图的第二个变体被称为 x 图,表示为
我正在尝试创建一个函数,该函数将两个函数作为参数并执行它们。 我尝试使用 cond ,但它只执行 action1 . (define seq-action (lambda (action1 act
我提前为我的原始英语道歉;我会尽量避免语法错误等。 两周前,我决定更新我对 Scheme(及其启示)的知识,同时实现我在手上获得的一些数学 Material ,特别是我注册的自动机理论和计算类(cla
Scheme中有没有函数支持分数的“div”操作? 意思是 - 11 格 2.75 = 4。 最佳答案 我认为你的问题的答案是:没有,但你可以定义它: #lang racket (define (di
我在scheme中实现合并排序,我必须通过定义两个辅助方法来实现:merge和split。 Merge 需要两个列表(已经按递增顺序)并将它们合并在一起。我这样做了如下: (define merge
尝试从终端加载方案文件。我创建了一个名为 test.scm 的文件,其中包含以下代码: (define (square x) (* x x)) (define (sum-of-squares x y)
我有以下代码: (define (howMany list) (if (null? list) 0 (+ 1 (howMany (cdr list))))) 如果我们执行以
我有点了解如何将基本函数(例如算术)转换为Scheme中的连续传递样式。 但如果函数涉及递归怎么办?例如, (define funname (lambda (arg0 arg1)
我正在尝试附加两个字符串列表 但我不知道如何在两个单词之间添加空格。 (define (string-concat lst1 lst2) (map string-append lst1
这个问题已经有答案了: How do I pass a list as a list of arguments in racket? (2 个回答) 已关闭 8 年前。 我有一个函数,它需要无限数量的
我对这段代码的工作方式感到困惑: (define m (list 1 2 3 '(5 8))) (let ((l (cdr m))) (set! l '(28 88))) ==>(1 2 3 (5 8
我正在为学校做一项计划作业,有一个问题涉及我们定义记录“类型”(作为列表实现)(代表音乐记录)。 我遇到的问题是我被要求创建一个过程来创建这些记录的列表,然后创建一个将记录添加到该列表的函数。这很简单
我有以下代码: (define (howMany list) (if (null? list) 0 (+ 1 (howMany (cdr list))))) 如果我们执行以
我正在尝试附加两个字符串列表 但我不知道如何在两个单词之间添加空格。 (define (string-concat lst1 lst2) (map string-append lst1
如何使用抽象列表函数(foldr、foldl、map 和 filter 编写函数),无需递归,消耗数字列表 (list a1 a2 a3 ...) 并产生交替和 a1 - a2 + a3 ...? 最
我试图找出在 Scheme 中发生的一些有趣的事情: (define last-pair (lambda (x) (if (null? (cdr x))
这个问题在这里已经有了答案: Count occurrence of element in a list in Scheme? (4 个答案) 关闭 8 年前。 我想实现一个函数来计算列表中元素出现
我正在尝试使用下面的代码获取方案中的导数。谁能告诉我哪里出错了?我已经尝试了一段时间了。 (define d3 (λ (e) (cond ((number? e) 0) ((e
我是一名优秀的程序员,十分优秀!