C# yield在WCF中的错误使用(二)
内容摘要
昨天写了《yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]》,引起了一些讨论。关于yield关键字这个语法糖背后的原理(C#编译器将它翻译成什么)其实挺简单,虽然
文章正文
昨天写了《yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]》,引起了一些讨论。关于yield关键字这个语法糖背后的原理(C#编译器将它翻译成什么)其实挺简单,虽然有时候因为误用它会导致一些问题,但是它本无过错。接下来,我们通过这篇短文简单地谈谈我所理解的yield。
目录
一、先看一个简单的例子
二、了解本质,只需要看看yield最终编译成什么
三、回到WCF的例子
一、先看一个简单的例子
我们现在看一个简单的例子。我们在一个Console应用中编写了如下一段简单的程序:返回类型为IEnumerable<string>的方法GetItems以yield return的方式返回一个包含三个字符串的集合,而在方法开始的时候我们打印一段文字表明定义在方法中的操作开始执行。在Main方法中,我们先调用GetItems方法将“集合对象”返回,然后调用其ToArray方法。在调用该方法之前我们打印一段文字表明对集合对象进行迭代。
yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]》中提到的例子,现在来解释为什么针对如下两段代码,前者抛出的异常不能被WCF正常处理,而后者可以。原因很简单——两段代码抛出异常的时机是不一样的。对于后者,异常在执行GetItems方法的时候会立即抛出来,WCF会捕获这个异常并作为应用级别的异常进行正常处理;对于前者,通过上面的分析我们知道异常实际上发生在对返回“集合对象”进行迭代的时候。具体是什么时候呢?其实就是对返回对象进行序列化的时候,此时抛出的异常将将会视为系统异常来处理。
public class DemoService : IDemoService
{
public IEnumerable<string> GetItems(string categoty)
{
if (string.IsNullOrEmpty(categoty))
{
throw new FaultException("Invalid category");
}
yield return "Foo";
yield return "Bar";
yield return "Baz";
}
}
我个人觉得这是WCF值得改进的地方,但是目前来说为了避免这样的问题,我推荐将WCF契约接口操作方法中的返回类型定义成数组,而不是IEnumerable或者IEnumerable<T>(顺便说一下,WCF针对Array、List以及其他集合类型的序列化/反序列化行为是一致的),但是我个人对IEnumerable或者IEnumerable<T>不排斥。
复制代码 代码如下:
public class DemoService : IDemoService
{
public IEnumerable<string> GetItems(string categoty)
{
if (string.IsNullOrEmpty(categoty))
{
throw new FaultException("Invalid category");
}
yield return "Foo";
yield return "Bar";
yield return "Baz";
}
}
public class DemoService : IDemoService
{
public IEnumerable<string> GetItems(string categoty)
{
if (string.IsNullOrEmpty(categoty))
{
throw new FaultException("Invalid category");
}
return new string[] { "Foo", "Bar", "Baz" };
}
}
我个人觉得这是WCF值得改进的地方,但是目前来说为了避免这样的问题,我推荐将WCF契约接口操作方法中的返回类型定义成数组,而不是IEnumerable或者IEnumerable<T>(顺便说一下,WCF针对Array、List以及其他集合类型的序列化/反序列化行为是一致的),但是我个人对IEnumerable或者IEnumerable<T>不排斥。
代码注释