猿问

令人费解的Enumerable.Cast InvalidCastException

令人费解的Enumerable.Cast InvalidCastException

以下抛出一个InvalidCastException。


IEnumerable<int> list = new List<int>() { 1 };

IEnumerable<long> castedList = list.Cast<long>();

Console.WriteLine(castedList.First());

为什么?


我正在使用Visual Studio 2008 SP1。


不负相思意
浏览 579回答 3
3回答

牛魔王的故事

下面是解决所有List<T>和Enumerable<T>转换问题。〜150行代码确保为所涉及的输入/输出类型定义至少一个显式或隐式转换运算符(如果不存在),就像你应该做的那样!using&nbsp;System;using&nbsp;System.Collections;using&nbsp;System.Collections.Generic;using&nbsp;System.Linq;using&nbsp;System.Text;using&nbsp;System.Reflection;namespace&nbsp;System.Collections.Generic&nbsp;//purposely&nbsp;in&nbsp;same&nbsp;namespace&nbsp;as&nbsp;List<T>,IEnumerable<T>,&nbsp;so&nbsp;extension&nbsp;methods&nbsp;are&nbsp;available&nbsp;with&nbsp;them{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;class&nbsp;Enumerable &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;List<TOutput>&nbsp;ConvertAll<TInput,TOutput>(&nbsp;this&nbsp;IEnumerable<TInput>&nbsp;input&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;BuildConvertedList<TInput,TOutput>(&nbsp;input,&nbsp;GetConverterDelegate<TInput,TOutput>()&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IEnumerable<TOutput>&nbsp;ConvertAll<TInput,TOutput>(&nbsp;this&nbsp;IEnumerable<TInput>&nbsp;input,&nbsp;bool&nbsp;lazy&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(lazy)&nbsp;return&nbsp;new&nbsp;LazyConverter<TInput,TOutput>(&nbsp;input,&nbsp;GetConverterDelegate<TInput,TOutput>()&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;BuildConvertedList<TInput,TOutput>(&nbsp;input,&nbsp;GetConverterDelegate<TInput,TOutput>()&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;List<TOutput>&nbsp;ConvertAll<TInput,TOutput>(&nbsp;this&nbsp;IEnumerable<TInput>&nbsp;input,&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;converter&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;BuildConvertedList<TInput,TOutput>(&nbsp;input,&nbsp;converter&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;List<TOutput>&nbsp;ConvertAll<TInput,&nbsp;TOutput>(&nbsp;this&nbsp;List<TInput>&nbsp;input&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;converter&nbsp;=&nbsp;GetConverterDelegate<TInput,TOutput>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;input.ConvertAll<TOutput>(&nbsp;converter&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;IEnumerable<TOutput>&nbsp;ConvertAll<TInput,&nbsp;TOutput>(&nbsp;this&nbsp;List<TInput>&nbsp;input,&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;converter,&nbsp;bool&nbsp;lazy&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(lazy)&nbsp;return&nbsp;new&nbsp;LazyConverter<TInput,&nbsp;TOutput>(&nbsp;input,&nbsp;converter&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;input.ConvertAll<TOutput>(&nbsp;converter&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;List<TOutput>&nbsp;ConvertAll<TInput,&nbsp;TOutput>(&nbsp;this&nbsp;List<TInput>&nbsp;input,&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;converter&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;input.ConvertAll<TOutput>(&nbsp;converter&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Used&nbsp;to&nbsp;manually&nbsp;build&nbsp;converted&nbsp;list&nbsp;when&nbsp;input&nbsp;is&nbsp;IEnumerable,&nbsp;since&nbsp;it&nbsp;doesn't&nbsp;have&nbsp;the&nbsp;ConvertAll&nbsp;method&nbsp;like&nbsp;the&nbsp;List&nbsp;does &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;List<TOutput>&nbsp;BuildConvertedList<TInput,TOutput>(&nbsp;IEnumerable<TInput>&nbsp;input,&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;converter&nbsp;){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List<TOutput>&nbsp;output&nbsp;=&nbsp;new&nbsp;List<TOutput>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(TInput&nbsp;input_item&nbsp;in&nbsp;input) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.Add(&nbsp;converter(&nbsp;input_item&nbsp;)&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;output; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;sealed&nbsp;class&nbsp;LazyConverter<TInput,&nbsp;TOutput>:&nbsp;IEnumerable<TOutput>,&nbsp;IEnumerator<TOutput> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;IEnumerable<TInput>&nbsp;input; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;converter; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;IEnumerator<TInput>&nbsp;input_enumerator; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;LazyConverter(&nbsp;IEnumerable<TInput>&nbsp;input,&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;converter&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.input&nbsp;=&nbsp;input; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.converter&nbsp;=&nbsp;converter; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.input_enumerator&nbsp;=&nbsp;input.GetEnumerator(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;IEnumerator<TOutput>&nbsp;GetEnumerator()&nbsp;{return&nbsp;this;}&nbsp;//IEnumerable<TOutput>&nbsp;Member &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerator&nbsp;IEnumerable.GetEnumerator()&nbsp;{return&nbsp;this;}&nbsp;//IEnumerable&nbsp;Member &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;Dispose()&nbsp;{input_enumerator.Dispose();}&nbsp;//IDisposable&nbsp;Member &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;TOutput&nbsp;Current&nbsp;{get&nbsp;{return&nbsp;converter.Invoke(&nbsp;input_enumerator.Current&nbsp;);}}&nbsp;//IEnumerator<TOutput>&nbsp;Member &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;object&nbsp;IEnumerator.Current&nbsp;{get&nbsp;{return&nbsp;Current;}}&nbsp;//IEnumerator&nbsp;Member &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;bool&nbsp;MoveNext()&nbsp;{return&nbsp;input_enumerator.MoveNext();}&nbsp;//IEnumerator&nbsp;Member &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;Reset()&nbsp;{input_enumerator.Reset();}&nbsp;//IEnumerator&nbsp;Member &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;sealed&nbsp;class&nbsp;TypeConversionPair:&nbsp;IEquatable<TypeConversionPair> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;readonly&nbsp;Type&nbsp;source_type; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;readonly&nbsp;Type&nbsp;target_type; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;int&nbsp;hashcode; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;TypeConversionPair(&nbsp;Type&nbsp;source_type,&nbsp;Type&nbsp;target_type&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.source_type&nbsp;=&nbsp;source_type; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.target_type&nbsp;=&nbsp;target_type; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//precalc/store&nbsp;hash,&nbsp;since&nbsp;object&nbsp;is&nbsp;immutable;&nbsp;add&nbsp;one&nbsp;to&nbsp;source&nbsp;hash&nbsp;so&nbsp;reversing&nbsp;the&nbsp;source&nbsp;and&nbsp;target&nbsp;still&nbsp;produces&nbsp;unique&nbsp;hash &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hashcode&nbsp;=&nbsp;(source_type.GetHashCode()&nbsp;+&nbsp;1)&nbsp;^&nbsp;target_type.GetHashCode(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;bool&nbsp;operator&nbsp;==(&nbsp;TypeConversionPair&nbsp;x,&nbsp;TypeConversionPair&nbsp;y&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((object)x&nbsp;!=&nbsp;null)&nbsp;return&nbsp;x.Equals(&nbsp;y&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((object)y&nbsp;!=&nbsp;null)&nbsp;return&nbsp;y.Equals(&nbsp;x&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;//x&nbsp;and&nbsp;y&nbsp;are&nbsp;both&nbsp;null,&nbsp;cast&nbsp;to&nbsp;object&nbsp;above&nbsp;ensures&nbsp;reference&nbsp;equality&nbsp;comparison &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;bool&nbsp;operator&nbsp;!=(&nbsp;TypeConversionPair&nbsp;x,&nbsp;TypeConversionPair&nbsp;y&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((object)x&nbsp;!=&nbsp;null)&nbsp;return&nbsp;!x.Equals(&nbsp;y&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((object)y&nbsp;!=&nbsp;null)&nbsp;return&nbsp;!y.Equals(&nbsp;x&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;//x&nbsp;and&nbsp;y&nbsp;are&nbsp;both&nbsp;null,&nbsp;cast&nbsp;to&nbsp;object&nbsp;above&nbsp;ensures&nbsp;reference&nbsp;equality&nbsp;comparison &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//TypeConversionPairs&nbsp;are&nbsp;equal&nbsp;when&nbsp;their&nbsp;source&nbsp;and&nbsp;target&nbsp;types&nbsp;are&nbsp;equal &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;bool&nbsp;Equals(&nbsp;TypeConversionPair&nbsp;other&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((object)other&nbsp;==&nbsp;null)&nbsp;return&nbsp;false;&nbsp;//cast&nbsp;to&nbsp;object&nbsp;ensures&nbsp;reference&nbsp;equality&nbsp;comparison &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;source_type&nbsp;==&nbsp;other.source_type&nbsp;&&&nbsp;target_type&nbsp;==&nbsp;other.target_type; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;bool&nbsp;Equals(&nbsp;object&nbsp;obj&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TypeConversionPair&nbsp;other&nbsp;=&nbsp;obj&nbsp;as&nbsp;TypeConversionPair; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((object)other&nbsp;!=&nbsp;null)&nbsp;return&nbsp;Equals(&nbsp;other&nbsp;);&nbsp;//call&nbsp;IEqualityComparer<TypeConversionPair>&nbsp;implementation&nbsp;if&nbsp;obj&nbsp;type&nbsp;is&nbsp;TypeConversionPair &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;//obj&nbsp;is&nbsp;null&nbsp;or&nbsp;is&nbsp;not&nbsp;of&nbsp;type&nbsp;TypeConversionPair;&nbsp;Equals&nbsp;shall&nbsp;not&nbsp;throw&nbsp;errors! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;int&nbsp;GetHashCode()&nbsp;{return&nbsp;hashcode;}&nbsp;//assigned&nbsp;in&nbsp;constructor;&nbsp;object&nbsp;is&nbsp;immutable &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;readonly&nbsp;Dictionary<TypeConversionPair,Delegate>&nbsp;conversion_op_cache&nbsp;=&nbsp;new&nbsp;Dictionary<TypeConversionPair,Delegate>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Uses&nbsp;reflection&nbsp;to&nbsp;find&nbsp;and&nbsp;create&nbsp;a&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;delegate&nbsp;for&nbsp;the&nbsp;given&nbsp;types. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Once&nbsp;a&nbsp;delegate&nbsp;is&nbsp;obtained,&nbsp;it&nbsp;is&nbsp;cached,&nbsp;so&nbsp;further&nbsp;requests&nbsp;for&nbsp;the&nbsp;delegate&nbsp;do&nbsp;not&nbsp;use&nbsp;reflection* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//(*the&nbsp;typeof&nbsp;operator&nbsp;is&nbsp;used&nbsp;twice&nbsp;to&nbsp;look&nbsp;up&nbsp;the&nbsp;type&nbsp;pairs&nbsp;in&nbsp;the&nbsp;cache) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Converter<TInput,&nbsp;TOutput>&nbsp;GetConverterDelegate<TInput,&nbsp;TOutput>() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Delegate&nbsp;converter; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TypeConversionPair&nbsp;type_pair&nbsp;=&nbsp;new&nbsp;TypeConversionPair(&nbsp;typeof(TInput),&nbsp;typeof(TOutput)&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Attempt&nbsp;to&nbsp;quickly&nbsp;find&nbsp;a&nbsp;cached&nbsp;conversion&nbsp;delegate. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock&nbsp;(conversion_op_cache)&nbsp;//synchronize&nbsp;with&nbsp;concurrent&nbsp;calls&nbsp;to&nbsp;Add &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(conversion_op_cache.TryGetValue(&nbsp;type_pair,&nbsp;out&nbsp;converter&nbsp;)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(Converter<TInput,&nbsp;TOutput>)converter; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Get&nbsp;potential&nbsp;conversion&nbsp;operators&nbsp;(target-type&nbsp;methods&nbsp;are&nbsp;ordered&nbsp;first) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodInfo[][]&nbsp;conversion_op_sets&nbsp;=&nbsp;new&nbsp;MethodInfo[2][]&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type_pair.target_type.GetMethods(&nbsp;BindingFlags.Static&nbsp;|&nbsp;BindingFlags.Public&nbsp;|&nbsp;BindingFlags.FlattenHierarchy&nbsp;), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type_pair.source_type.GetMethods(&nbsp;BindingFlags.Static&nbsp;|&nbsp;BindingFlags.Public&nbsp;|&nbsp;BindingFlags.FlattenHierarchy&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Find&nbsp;appropriate&nbsp;conversion&nbsp;operator, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//favoring&nbsp;operators&nbsp;on&nbsp;target&nbsp;type&nbsp;in&nbsp;case&nbsp;functionally&nbsp;equivalent&nbsp;operators&nbsp;exist, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//since&nbsp;the&nbsp;target&nbsp;type's&nbsp;conversion&nbsp;operator&nbsp;may&nbsp;have&nbsp;access&nbsp;to&nbsp;an&nbsp;appropriate&nbsp;constructor &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//or&nbsp;a&nbsp;common&nbsp;instance&nbsp;cache&nbsp;(i.e.&nbsp;immutable&nbsp;objects&nbsp;may&nbsp;be&nbsp;cached&nbsp;and&nbsp;reused). &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;s&nbsp;=&nbsp;0;&nbsp;s&nbsp;<&nbsp;conversion_op_sets.Length;&nbsp;s++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodInfo[]&nbsp;conversion_ops&nbsp;=&nbsp;conversion_op_sets[s]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;m&nbsp;=&nbsp;0;&nbsp;m&nbsp;<&nbsp;conversion_ops.Length;&nbsp;m++) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodInfo&nbsp;mi&nbsp;=&nbsp;conversion_ops[m]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((mi.Name&nbsp;==&nbsp;"op_Explicit"&nbsp;||&nbsp;mi.Name&nbsp;==&nbsp;"op_Implicit")&nbsp;&&&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mi.ReturnType&nbsp;==&nbsp;type_pair.target_type&nbsp;&& &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mi.GetParameters()[0].ParameterType.IsAssignableFrom(&nbsp;type_pair.source_type&nbsp;))&nbsp;//Assuming&nbsp;op_Explicit&nbsp;and&nbsp;op_Implicit&nbsp;always&nbsp;have&nbsp;exactly&nbsp;one&nbsp;parameter. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;converter&nbsp;=&nbsp;Delegate.CreateDelegate(&nbsp;typeof(Converter<TInput,&nbsp;TOutput>),&nbsp;mi&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock&nbsp;(conversion_op_cache)&nbsp;//synchronize&nbsp;with&nbsp;concurrent&nbsp;calls&nbsp;to&nbsp;TryGetValue &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conversion_op_cache.Add(&nbsp;type_pair,&nbsp;converter&nbsp;);&nbsp;//Cache&nbsp;the&nbsp;conversion&nbsp;operator&nbsp;reference&nbsp;for&nbsp;future&nbsp;use. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(Converter<TInput,&nbsp;TOutput>)converter; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(TInput&nbsp;x)&nbsp;=>&nbsp;((TOutput)Convert.ChangeType(&nbsp;x,&nbsp;typeof(TOutput)&nbsp;));&nbsp;//this&nbsp;works&nbsp;well&nbsp;in&nbsp;the&nbsp;absence&nbsp;of&nbsp;conversion&nbsp;operators&nbsp;for&nbsp;types&nbsp;that&nbsp;implement&nbsp;IConvertible &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//throw&nbsp;new&nbsp;InvalidCastException(&nbsp;"Could&nbsp;not&nbsp;find&nbsp;conversion&nbsp;operator&nbsp;to&nbsp;convert&nbsp;"&nbsp;+&nbsp;type_pair.source_type.FullName&nbsp;+&nbsp;"&nbsp;to&nbsp;"&nbsp;+&nbsp;type_pair.target_type.FullName&nbsp;+&nbsp;"."&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}}样品用途:using&nbsp;System;using&nbsp;System.Collections.Generic;namespace&nbsp;ConsoleApplication1{ &nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;Program &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;Main(string[]&nbsp;args) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List<string>&nbsp;list&nbsp;=&nbsp;new&nbsp;List<string>(new&nbsp;string[]&nbsp;{&nbsp;"abcde",&nbsp;"abcd",&nbsp;"abc"/*will&nbsp;break&nbsp;length&nbsp;constraint*/,&nbsp;"ab",&nbsp;"a"&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Uncomment&nbsp;line&nbsp;below&nbsp;to&nbsp;see&nbsp;non-lazy&nbsp;behavior.&nbsp;&nbsp;All&nbsp;items&nbsp;converted&nbsp;before&nbsp;method&nbsp;returns,&nbsp;and&nbsp;will&nbsp;fail&nbsp;on&nbsp;third&nbsp;item,&nbsp;which&nbsp;breaks&nbsp;the&nbsp;length&nbsp;constraint. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//List<ConstrainedString>&nbsp;constrained_list&nbsp;=&nbsp;list.ConvertAll<string,ConstrainedString>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerable<ConstrainedString>&nbsp;constrained_list&nbsp;=&nbsp;list.ConvertAll<string,ConstrainedString>(&nbsp;true&nbsp;);&nbsp;//lazy&nbsp;conversion;&nbsp;conversion&nbsp;is&nbsp;not&nbsp;attempted&nbsp;until&nbsp;that&nbsp;item&nbsp;is&nbsp;read &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(ConstrainedString&nbsp;constrained_string&nbsp;in&nbsp;constrained_list)&nbsp;//will&nbsp;not&nbsp;fail&nbsp;until&nbsp;the&nbsp;third&nbsp;list&nbsp;item&nbsp;is&nbsp;read/converted &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Console.WriteLine(&nbsp;constrained_string.ToString()&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;class&nbsp;ConstrainedString &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;string&nbsp;value; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;ConstrainedString(&nbsp;string&nbsp;value&nbsp;){this.value&nbsp;=&nbsp;Constrain(value);} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;Constrain(&nbsp;string&nbsp;value&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(value.Length&nbsp;>&nbsp;3)&nbsp;return&nbsp;value; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;ArgumentException("String&nbsp;length&nbsp;must&nbsp;be&nbsp;>&nbsp;3!"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;explicit&nbsp;operator&nbsp;ConstrainedString(&nbsp;string&nbsp;value&nbsp;){return&nbsp;new&nbsp;ConstrainedString(&nbsp;value&nbsp;);} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;string&nbsp;ToString()&nbsp;{return&nbsp;value;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}}
随时随地看视频慕课网APP
我要回答