C#的yield return返回不可序列化的IEnumerable和IEnumerator
.NET中的大多数常见IEnumerable和IEnumerator都是可以序列化的(有Serializable特性)。比如Array,Dictionary
注意其中已0开始的一维数组会返回Array.SZArrayEnumerator迭代器(其IEnumerable
但是yield return返回产生的IEnumerable和IEnumerator是不可序列化的,这一点很重要!尤其在扩应用程序域(AppDomain)程序数据交互的情景,此时要求数据要么可序列化要么继承MarshalByRefObject,也就是所谓的按值封送和按引用封送。
通过一个简单的程序就可以验证:
static void Main()
{
Console.WriteLine(able1().GetType());
Console.WriteLine(able2().GetType());
Console.WriteLine(tor1().GetType());
Console.WriteLine(tor2().GetType());
}
static IEnumerable
{
for (int i = 0; i < 5; i++)
{
yield return i + 1;
}
}
static IEnumerable
{
return new int[] { 1, 2, 3, 4, 5 };
}
static IEnumerator
{
for (int i = 0; i < 5; i++)
{
yield return i + 1;
}
}
static IEnumerator
{
return ((IEnumerable
}
输出:
Mgen.Program+
System.Int32[]
Mgen.Program+
System.SZArrayHelper+SZGenericArrayEnumerator`1[System.Int32]
第二个和第四个类都是可序列化的,而用yield return返回的对象都是编译器自动生成的,且都不是可序列化的,下面是Reflector下的两个类定义:
[CompilerGenerated]
private sealed class
[CompilerGenerated]
private sealed class
上面提到过这样的IEnumerable和IEnumerator无法在跨应用程序域中进行封送。写这篇文章也是由于今天遇到这种问题:
class Program: MarshalByRefObject
{
static void Main()
{
//创建应用程序域
AppDomain appDomain = AppDomain.CreateDomain("new appdomain");
//在另一个应用程序域中创建Program对象
Program pro = (Program)appDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName,
typeof(Program).FullName);
//此处异常:返回值必须可以被序列化!
IEnumerator
}
IEnumerator
{
for (int i = 0; i < 5; i++)
{
yield return i + 1;
}
}
}
解决方案当然就是不用yield return或者自定义自己的可序列化的迭代器。
当然yield return在某些时候还是很有必要的,当然把编译器yield return产生的非可序列化对象做一个简单的包装也可以在跨应用程序域中使用。
下面是完整的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.Runtime.Remoting;
using System.Reflection;
namespace Mgen.TTC
{
class Program : MarshalByRefObject
{
static void Main()
{
//创建应用程序域
AppDomain appDomain = AppDomain.CreateDomain("new appdomain");
//在另一个应用程序域中创建Program对象
Program pro = (Program)appDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName,
typeof(Program).FullName);
IEnumerator
while (iter.MoveNext())
Console.WriteLine(iter.Current);
Console.WriteLine("是否是透明代理: {0}", RemotingServices.IsTransparentProxy(iter));
}
IEnumerator
{
for (int i = 0; i < 5; i++)
{
yield return i + 1;
}
}
IEnumerator
{
return new MyEnumerator
}
}
class MyEnumerator
{
IEnumerator
public MyEnumerator(IEnumerator
{
iter = i;
}
public T Current
{
get { return iter.Current; }
}
public void Dispose()
{
iter.Dispose();
}
object IEnumerator.Current
{
get { return ((IEnumerator)iter).Current; }
}
public bool MoveNext()
{
return iter.MoveNext();
}
public void Reset()
{
iter.Reset();
}
}
}
输出:
1
2
3
4
5
是否是透明代理: True
OK,迭代器可以被使用且属于透明代理(在另一个应用程序域)。
创造与魔法 安卓版v1.0.0750
创造与魔法是一款开放世界手游,在游戏中玩家可探索这个奇妙的世
创造与魔法修改版 最新版v1.0.0750
创造与魔法无限点券版是款探索冒险游戏,该款游戏的操作还是蛮自
战争与文明官方版本 安卓版v1.7.16
战争与文明是一款由上海邮通科技有限公司开发的战争策略游戏,这
迷你世界0元领皮肤无限迷你币版 最新安卓版v1.43.0
迷你世界0元购买皮肤版是这款开放沙盒冒险建造游戏的特殊破解版
创造与魔法无限经验版 安卓版v1.0.0750
创造与魔法无限经验版是款可以改造环境,整个游戏的自由度还是蛮