最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
C#的yield return返回不可序列化的IEnumerable和IEnumerator
时间:2022-06-25 04:05:57 编辑:袖梨 来源:一聚教程网
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,迭代器可以被使用且属于透明代理(在另一个应用程序域)。
相关文章
- 《魔兽世界》缴械行动任务完成方法 04-27
- 《重装岚影》特色内容介绍 04-27
- 《崩坏星穹铁道》新手0氛开服必养角色推荐 04-27
- 《魔兽世界》吃鸡模式最厉害技能介绍 04-27
- 《百英雄传》莫罗乌斯位置介绍 04-27
- 《csgo》玉麒麟个人简介介绍 04-27