C #'s yield return returns non-serializable IEnumerable and IEnumerator

Source: Internet
Author: User

C #'s yield return returns non-serializable IEnumerable and IEnumerator

In. NET, most common IEnumerable and IEnumerator can be serialized (with the Serializable feature ). For example, Array, Dictionary <K, V>, HashSet <T>, List <T>, sorted List, Queue <T>, Stack <T>, String, ResourceSet ...... And so on. Generally, the GetEnumerator method of the serializable IEnumerable will return an identical serializable iterator (IEnumerator ).

Note that a one-dimensional Array starting with 0 will return Array. SZArrayEnumerator (the GetEnumerator of IEnumerable <T> shows that System is returned when the interface is executed. SZArrayHelper. SZGenericArrayEnumerator <T> iterator ). Other types of arrays return the Array. ArrayEnumerator iterator. Both are serializable.

However, the IEnumerable and IEnumerator generated by yield return cannot be serialized, which is very important! Especially when the application domain (AppDomain) program data interaction is expanded, data must either be serializable or inherit from MarshalByRefObject, that is, value-based and reference-based messages.

It can be verified through a simple program:

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 ();

}

 

Output:

Mgen. Program + <able1> d _ 0

System. Int32 []

Mgen. Program + <tor1> d _ 4

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

 

The second and fourth classes are both serializable, and the objects returned with yield return are automatically generated by the compiler and are not serializable. Below are two class definitions under 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

 

 

As mentioned above, IEnumerable and IEnumerator cannot be sent across application domains. This article is also due to the following problems:

Class Program: MarshalByRefObject

{

Static void Main ()

{

// Create an application domain

AppDomain appDomain = AppDomain. CreateDomain ("new appdomain ");

// Create a Program object in another application domain

Program pro = (Program) appDomain. CreateInstanceAndUnwrap (Assembly. GetExecutingAssembly (). FullName,

Typeof (Program). FullName );

// Exception: the returned value must be serializable!

IEnumerator <int> iter = pro. test ();

 

}

 

IEnumerator <int> test ()

{

For (int I = 0; I <5; I ++)

{

Yield return I + 1;

}

}

}

 

 

The solution is of course not to use yield return or customize its own serializable iterator.

Of course, yield return is quite necessary in some cases. Of course, it can be used to make a simple packaging of non-serializable objects generated by the compiler yield return across application domains.

 

 

The complete code is as follows:

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 ()

{

// Create an application domain

AppDomain appDomain = AppDomain. CreateDomain ("new appdomain ");

// Create a Program object in another application domain

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 ("Whether the proxy is transparent: {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 ();

}

}

}

 

 

 

Output:

1

2

3

4

5

Whether it is a transparent Proxy: True

 

OK. The iterator can be used and belongs to a transparent proxy (in another application domain ).

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.