C#:从System.Typedynamic分析

我有一个types,一个string和一个对象。

有什么办法可以调用parsing方法或dynamic的stringtypes转换?

基本上我如何删除这个逻辑中的if语句

object value = new object(); String myString = "something"; Type propType = p.PropertyType; if(propType == Type.GetType("DateTime")) { value = DateTime.Parse(myString); } if (propType == Type.GetType("int")) { value = int.Parse(myString); } 

而且做更多这样的事情。

 object value = new object(); String myString = "something"; Type propType = p.PropertyType; //this doesn't actually work value = propType .Parse(myString); 

TypeDescriptor来拯救:

 var converter = TypeDescriptor.GetConverter(propType); var result = converter.ConvertFrom(myString); 

要集成到TypeConverter基础结构中,实现您自己的TypeConverter并使用TypeConverter装饰要转换的类

这应该适用于所有原始types,以及实现IConvertibletypes

 public static T ConvertTo<T>(object value) { return (T)Convert.ChangeType(value, typeof(T)); } 

编辑:实际上在你的情况下,你不能使用generics(至less不容易)。 相反,你可以这样做:

 object value = Convert.ChangeType(myString, propType); 

我碰到这个问题,这就是我解决它的方法:

 value = myString; var parse = propType.GetMethod("Parse", new[] { typeof(string) }); if (parse != null) { value = parse.Invoke(null, new object[] { value }); } 

…它为我工作。

总结一下,你正试图在对象types上find一个只有一个string作为参数的静态“Parse”方法。 如果你find这样一个方法,然后用你想要转换的string参数调用它。 由于p是我的types的PropertyInfo,我结束了这个方法通过设置我的实例的值如下:

 p.SetValue(instance, value, null); 

取决于你想完成什么。

1)如果你只是想清理你的代码,并删除重复的types检查,那么你想要做的是集中你的检查方法,

 public static T To<T> (this string stringValue) { T value = default (T); if (typeof (T) == typeof (DateTime)) { // insert custom or convention System.DateTime // deserialization here ... } // ... add other explicit support here else { throw new NotSupportedException ( string.Format ( "Cannot convert type [{0}] with value [{1}] to type [{2}]." + " [{2}] is not supported.", stringValue.GetType (), stringValue, typeof (T))); } return value; } 

2)如果你想要一些更基本的types的概括,你可以尝试像托马斯·列维斯克 ( Thomas Levesque)所 build议的那样 – 尽pipe事实上,我自己并没有尝试过这个,我对Convert [近期]扩展并不熟悉。 也是一个非常好的build议。

3)实际上,您可能希望将上面的1)和2)合并到一个扩展中,以便支持基本的值转换和明确的复杂types支持。

4)如果你想完全“免提”,那么你也可以默认为普通的旧序列化[Xml或Binary,或/]。 当然,这限制了你的input – 也就是说所有的input必须是一个适当的Xml或Binary格式。 老实说,这可能是矫枉过正,但值得一提。

当然,所有这些方法基本上都是一样的。 它们中没有任何一个是有魔力的,在某些时候, 有人正在执行线性查找(无论是通过连续的if-clause或通过.Net转换和序列化工具隐藏的查询)。

5)如果你想提高性能,那么你想要做的是改善转换过程中的“查找”部分。 创build一个显式的“支持types”列表,每个types对应一个数组中的索引。 然后指定索引,而不是在呼叫中指定types。

编辑:所以,虽然线性查找是整洁和快速,它也会发生在我这将更快,如果消费者只是获得转换函数,并直接调用它们。 也就是说,消费者知道什么types想要转换为[这是给定的],所以如果需要一次转换多个项目,

 // S == source type // T == target type public interface IConvert<S> { // consumers\infrastructure may now add support int AddConversion<T> (Func<S, T> conversion); // gets conversion method for local consumption Func<S, T> GetConversion<T> (); // easy to use, linear look up for one-off conversions T To<T> (S value); } public class Convert<S> : IConvert<S> { private class ConversionRule { public Type SupportedType { get; set; } public Func<S, object> Conversion { get; set; } } private readonly List<ConversionRule> _map = new List<ConversionRule> (); private readonly object _syncRoot = new object (); public void AddConversion<T> (Func<S, T> conversion) { lock (_syncRoot) { if (_map.Any (c => c.SupportedType.Equals (typeof (T)))) { throw new ArgumentException ( string.Format ( "Conversion from [{0}] to [{1}] already exists. " + "Cannot add new conversion.", typeof (S), typeof (T))); } ConversionRule conversionRule = new ConversionRule { SupportedType = typeof(T), Conversion = (s) => conversion (s), }; _map.Add (conversionRule); } } public Func<S, T> GetConversion<T> () { Func<S, T> conversionMethod = null; lock (_syncRoot) { ConversionRule conversion = _map. SingleOrDefault (c => c.SupportedType.Equals (typeof (T))); if (conversion == null) { throw new NotSupportedException ( string.Format ( "Conversion from [{0}] to [{1}] is not supported. " + "Cannot get conversion.", typeof (S), typeof (T))); } conversionMethod = (value) => ConvertWrap<T> (conversion.Conversion, value); } return conversionMethod; } public T To<T> (S value) { Func<S, T> conversion = GetConversion<T> (); T typedValue = conversion (value); return typedValue; } // private methods private T ConvertWrap<T> (Func<S, object> conversion, S value) { object untypedValue = null; try { untypedValue = conversion (value); } catch (Exception exception) { throw new ArgumentException ( string.Format ( "Unexpected exception encountered during conversion. " + "Cannot convert [{0}] [{1}] to [{2}].", typeof (S), value, typeof (T)), exception); } if (!(untypedValue is T)) { throw new InvalidCastException ( string.Format ( "Converted [{0}] [{1}] to [{2}] [{3}], " + "not of expected type [{4}]. Conversion failed.", typeof (S), value, untypedValue.GetType (), untypedValue, typeof (T))); } T typedValue = (T)(untypedValue); return typedValue; } } 

它会被用作

 // as part of application innitialization IConvert<string> stringConverter = container.Resolve<IConvert<string>> (); stringConverter.AddConversion<int> (s => Convert.ToInt32 (s)); stringConverter.AddConversion<Color> (s => CustomColorParser (s)); ... // a consumer elsewhere in code, say a Command acting on // string input fields of a form // // NOTE: stringConverter could be injected as part of DI // framework, or obtained directly from IoC container as above int someCount = stringConverter.To<int> (someCountString); Func<string, Color> ToColor = stringConverter.GetConversion <Color> (); IEnumerable<Color> colors = colorStrings.Select (s => ToColor (s)); 

我更喜欢后一种方法,因为它使您可以完全控制转换。 如果使用Castle Windsor或Unity这样的控制反转(IoC)容器,则可以为您完成此项服务的注入。 另外,因为它是基于实例的,所以可以有多个实例,每个实例都有自己的一组转换规则 – 例如,如果您有多个用户控件,每个都会生成它自己的DateTime或其他复杂的string格式。

哎呀,即使你想支持单个目标types的多个转换规则,这也是可能的,你只需要扩展方法参数来指定哪一个。

查看string在技术上是不可能的,并确定它代表的是哪种types。

所以,对于任何通用的方法,您至less需要:

  1. 要parsing的string
  2. 用于parsing的types。

看看静态Convert.ChangeType()方法。

这似乎是你想要做的(至less如果涉及的types是你不能修改源的types)需要鸭子打字 ,这是不是在C#

如果你需要做很多事情,我会把这个逻辑放到一个可以传递“myString”和“propType”的类或方法中,然后返回值。 在这种方法中,您只需执行上面的if链,并在find匹配的值时返回值。 你必须手动列出所有可能的types,但是你只需要做一次。