C#的yield return返回不可序列化的IEnumerable和IEnumerator

C#的yield return返回不可序列化的IEnumerable和IEnumerator

.NET中的大多数常见IEnumerable和IEnumerator都是可以序列化的(有Serializable特性)。比如Array,Dictionary<K,V>, HashSet<T>, List<T>, LinkedList, Queue<T>, Stack<T>, String, ResourceSet……等等类。而且一般可序列化的IEnumerable的GetEnumerator方法会返回一个同样可序列化的迭代器(IEnumerator)。

注意其中已0开始的一维数组会返回Array.SZArrayEnumerator迭代器(其IEnumerable<T>的GetEnumerator显示接口执行还会返回System.SZArrayHelper.SZGenericArrayEnumerator<T>迭代器)。而其他类型的数组会返回Array.ArrayEnumerator迭代器。三者也都是可序列化的

但是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<int> able1()

        {

            for (int i = 0; i < 5; i++)

            {

                yield return i + 1;

            }

        }

 

        static IEnumerable<int> able2()

        {

            return new int[] { 1, 2, 3, 4, 5 };

        }

 

        static IEnumerator<int> tor1()

        {

            for (int i = 0; i < 5; i++)

            {

                yield return i + 1;

            }

        }

        static IEnumerator<int> tor2()

        {

            return ((IEnumerable<int>)new int[] { 1, 2, 3, 4, 5 }).GetEnumerator();

        }

 

输出:

Mgen.Program+<able1>d__0

System.Int32[]

Mgen.Program+<tor1>d__4

System.SZArrayHelper+SZGenericArrayEnumerator`1[System.Int32]

 

第二个和第四个类都是可序列化的,而用yield return返回的对象都是编译器自动生成的,且都不是可序列化的,下面是Reflector下的两个类定义:

    [CompilerGenerated]

    private sealed class <able1>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable

 

    [CompilerGenerated]

    private sealed class <tor1>d__4 : IEnumerator<int>, IEnumerator, IDisposable

 

 

上面提到过这样的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<int> iter = pro.test();

 

        }

 

        IEnumerator<int> test()

        {

            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<int> iter = pro.test();

 

 

            while (iter.MoveNext())

                Console.WriteLine(iter.Current);

 

            Console.WriteLine("是否是透明代理: {0}", RemotingServices.IsTransparentProxy(iter));

        }

 

        IEnumerator<int> internal_test()

        {

            for (int i = 0; i < 5; i++)

            {

                yield return i + 1;

            }

        }

 

        IEnumerator<int> test()

        {

            return new MyEnumerator<int>(internal_test());

        }

    }

 

    class MyEnumerator<T> : MarshalByRefObject, IEnumerator<T>

    {

        IEnumerator<T> iter;

        public MyEnumerator(IEnumerator<T> i)

        {

            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,迭代器可以被使用且属于透明代理(在另一个应用程序域)。

时间: 2024-12-26 21:48:23

C#的yield return返回不可序列化的IEnumerable和IEnumerator的相关文章

c#中IEnumerable简单实现及 yield return 语法糖

c#中IEnumerable简介及简单实现 IEnumerable这个接口在MSDN上是这么说的,它是一个公开枚举数,该枚举数支持在非泛型集合上进行简单的迭代.换句话说,对于所有数组的遍历,都来自IEnumerable,那么我们就可以利用这个特性,来定义一个能够遍历字符串的通用方法. 下面先贴出code.  代码如下 复制代码 using System;using System.Collections.Generic;using System.Linq;using System.Text;usi

java递归 if() return返回到哪里?

问题描述 java递归 if() return返回到哪里? 学习归并排序时,遇到递归的思想.测试输入 mergesortexample单步调试到,if (hi<=lo) return;当hi=0,lo=0时,执行return,在我理解中,return就是退出方法了,为何会跳到 sort(amid+1hi);而且此时,lo=0,hi=1? private static void sort(Comparable[] aint loint hi){ //将数组a[lo hi]排序 if (hi<=l

&amp;amp;lt;递归&amp;amp;gt;return返回值中 &amp;amp;amp;&amp;amp;amp; 是什么用法?

问题描述 <递归>return返回值中 && 是什么用法? 首先,本人新手,请大神解决基础题一题. 如题: 用递归判断数列是否为递增,答案如下: bool fun(int a[], int n) { if(n= =1) return true; if( n= =2 ) return a[n-1] >= a[n-2]; return fun( a,n-1) && ( a[n-1] >= a[n-2] );_ } 最后一句中的&&是个什么

C# 调用存储过程操作 OUTPUT参数和Return返回值

本文转载:http://www.cnblogs.com/libingql/archive/2010/05/02/1726104.html 存储过程是存放在数据库服务器上的预先编译好的sql语句.使用存储过程,可以直接在数据库中存储并运行功能强大的任务.存储过程在第一应用程序执行时进行语法检查和编译,编译好的版本保存在高速缓存中.在执行重复任务时,存储过程可以提高性能和一致性.由于存储过程可以将一系列对数据库的操作放在数据库服务器上执行,因而可以降低Web服务器的负载,提高整个系统的性能.   1

C#中yield return用法

转载:http://www.jb51.net/article/54810.htm         http://www.cnblogs.com/HunterWei/archive/2012/06/13/csharpyieldreturn.html         http://www.cnblogs.com/nankezhishi/archive/2009/03/20/1418086.html         http://kb.cnblogs.com/page/42580/ 简单地说,当希望获

yield return (string)de.Value;

问题描述 这样写有错吗.为什么老是提示"应输入;" 解决方案 解决方案二:yieldreturn(string)de.Value;这也是一部分?解决方案三:这是一个上传类里面的publicnewIEnumeratorGetEnumerator(){foreach(DictionaryEntrydeinDictionary){yieldreturn(string)de.Value;}}

C# 2.0 Specification(迭代器)(二)

22.4 yield 语句yield语句用于迭代器块以产生一个枚举器对象值,或表明迭代的结束. embedded-statement:(嵌入语句)...yield-statement(yield语句) yield-statement:(yield 语句)yield return expression ;yield break ; 为了确保和现存程序的兼容性,yield并不是一个保留字,并且 yield只有在紧邻return或break关键词之前才具有特别的意义.而在其他上下文中,它可以被用作标识

C# 2.0 Specification(二)

19.1.5泛型方法在某些情形下,类型参数对于整个类不是必需的,而只对特定方法内是必需的.经常,当创建一个接受泛型类型作为参数的方法时就是这样.例如,当使用早先描述的Stack<T>类时,一个通用的模式可能是在一行中压入多个值,在一个单一的调用中写一个方法这么做也是很方便的.对于特定的构造类型,例如Stack<int>,这个方法看起来像这样. void PushMultiple(Stack<int> stack ,params int[] values) { forea

C#2.0简介

C#2.0简介 C# 2.0引入了很多语言扩展,最重要的就是泛型(Generics).匿名方法(Anonymous Methods).迭代器(Iterators)和不完全类型(Partial Types).• 泛型允许类.结构.接口.委托和方法通过它们所存贮和操作的数据的类型来参数化.泛型是很有用的,因为它提供了更为强大的编译期间类型检查,需要更少的数据类型之间的显式转换,并且减少了对装箱操作的需要和运行时的类型检查.• 匿名方法允许在需要委托值时能够以"内联(in-line)"的方式