是否可以序列化包含 yield 语句的方法(或包含此类方法的类),以便在重新水化该类时,保留生成的迭代器的内部状态?
最佳答案
是的,你可以做到这一点。注意事项。
可以在此处找到使用 yield 序列化方法、反序列化和继续的示例:http://www.agilekiwi.com/dotnet/CountingDemo.cs (Web Archive Link)。
一般来说,尝试序列化而不做一些额外的工作会失败。这是因为编译器生成的类没有用 Serializable 属性标记。但是,您可以解决这个问题。
我会注意到它们没有标记为可序列化的原因是因为它们是一个实现细节并且会在未来版本中发生重大更改,因此您可能无法在较新版本中反序列化它。
与我在 how to serialize anonymous delegates 上提出的问题相关,这也适用于这种情况。
这是“hack”的源代码:
// Copyright © 2007 John M Rusk (http://www.agilekiwi.com)
//
// You may use this source code in any manner you wish, subject to
// the following conditions:
//
// (a) The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// (b) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;
namespace AgileKiwi.PersistentIterator.Demo
{
/// <summary>
/// This is the class we will enumerate over
/// </summary>
[Serializable]
public class SimpleEnumerable
{
public IEnumerator<string> Foo()
{
yield return "One";
yield return "Two";
yield return "Three";
}
#region Here is a more advanced example
// This shows that the solution even works for iterators which call other iterators
// See SimpleFoo below for a simpler example
public IEnumerator<string> AdvancedFoo()
{
yield return "One";
foreach (string s in Letters())
yield return "Two " + s;
yield return "Three";
}
private IEnumerable<string> Letters()
{
yield return "a";
yield return "b";
yield return "c";
}
#endregion
}
/// <summary>
/// This is the command-line program which calls the iterator and serializes the state
/// </summary>
public class Program
{
public static void Main()
{
// Create/restore the iterator
IEnumerator<string> e;
if (File.Exists(StateFile))
e = LoadIterator();
else
e = (new SimpleEnumerable()).Foo(); // start new iterator
// Move to next item and display it.
// We can't use foreach here, because we only want to get ONE
// result at a time.
if (e.MoveNext())
Console.WriteLine(e.Current);
else
Console.WriteLine("Finished. Delete the state.xml file to restart");
// Save the iterator state back to the file
SaveIterator(e);
// Pause if running from the IDE
if (Debugger.IsAttached)
{
Console.Write("Press any key...");
Console.ReadKey();
}
}
static string StateFile
{
get {
return Path.Combine(
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
"State.xml");
}
}
static IEnumerator<string> LoadIterator()
{
using (FileStream stream = new FileStream(StateFile, FileMode.Open))
{
ISurrogateSelector selector = new EnumerationSurrogateSelector();
IFormatter f = new SoapFormatter(selector, new StreamingContext());
return (IEnumerator<string>)f.Deserialize(stream);
}
}
static void SaveIterator(IEnumerator<string> e)
{
using (FileStream stream = new FileStream(StateFile, FileMode.Create))
{
ISurrogateSelector selector = new EnumerationSurrogateSelector();
IFormatter f = new SoapFormatter(selector, new StreamingContext());
f.Serialize(stream, e);
}
#region Note: The above code puts the name of the compiler-generated enumerator class...
// into the serialized output. Under what circumstances, if any, might a recompile result in
// a different class name? I have not yet investigated what the answer might be.
// I suspect MS provide no guarantees in that regard.
#endregion
}
}
#region Helper classes to serialize iterator state
// See http://msdn.microsoft.com/msdnmag/issues/02/09/net/#S3
class EnumerationSurrogateSelector : ISurrogateSelector
{
ISurrogateSelector _next;
public void ChainSelector(ISurrogateSelector selector)
{
_next = selector;
}
public ISurrogateSelector GetNextSelector()
{
return _next;
}
public ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
{
if (typeof(System.Collections.IEnumerator).IsAssignableFrom(type))
{
selector = this;
return new EnumeratorSerializationSurrogate();
}
else
{
//todo: check this section
if (_next == null)
{
selector = null;
return null;
}
else
{
return _next.GetSurrogate(type, context, out selector);
}
}
}
}
// see http://msdn.microsoft.com/msdnmag/issues/02/09/net/#S3
class EnumeratorSerializationSurrogate : ISerializationSurrogate
{
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
foreach(FieldInfo f in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
info.AddValue(f.Name, f.GetValue(obj));
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context,
ISurrogateSelector selector)
{
foreach (FieldInfo f in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
f.SetValue(obj, info.GetValue(f.Name, f.FieldType));
return obj;
}
}
#endregion
}
关于c# - 序列化和 Yield 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3294224/
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
我明白了defa(&block)block.call(self)end和defa()yieldselfend导致相同的结果,如果我假设有这样一个blocka{}。我的问题是-因为我偶然发现了一些这样的代码,它是否有任何区别或者是否有任何优势(如果我不使用变量/引用block):defa(&block)yieldselfend这是一个我不理解&block用法的具体案例:defrule(code,name,&block)@rules=[]if@rules.nil?@rules 最佳答案 我能想到的唯一优点就是自省(introspecti
我想从then子句中访问case语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案
假设我必须(小型到中型)阵列:tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]如何确定tokens是否以相同的顺序包含template的所有条目?(请注意,在上面的示例中,应忽略第一个“ccc”,从而由于最后一个“ccc”而导致匹配。) 最佳答案 这适用于您的示例数据。tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]po
如何在Ruby的if语句中检查bash命令的返回值(true/false)。我想要这样的东西,if("/usr/bin/fswscell>/dev/null2>&1")has_afs="true"elsehas_afs="false"end它会提示以下错误含义,它总是返回true。(irb):5:warning:stringliteralincondition正确的语法是什么?更新:/usr/bin/fswscell寻找afs安装和运行状态。它会抛出这样的字符串,Thisworkstationbelongstocell如果afs没有运行,命令以状态1退出 最