扩展Convert.ChangeType以根据请求生成用户定义的类型

时间:2010-10-02 20:38:27

标签: c# type-conversion

鉴于课程:

public class Foo
{
    public string Name { get; set; }
}

是否可以通过Convert.ChangeType:

从字符串创建Foo实例
Type type = typeof(Foo);
object value = "one";

value = System.Convert.ChangeType(value, type);

这是第三方API尝试重建对象的方式。有人提到这可能是隐式运算符,但从我的理解中,我将执行以下操作,而不是创建对象:

Foo foo = new Foo() { Name = "one" };
string fooAsString = foo;  // implicit conversion -- no cast needed

有没有办法以这种方式创建对象?此外,如果有另一种方法,我可以更改Convert.ChangeType。

更新 我问的原因是因为它抛出异常:

  

从'System.String'转换为无效   'JibbaJabba +富'。

并添加运算符无法解决问题。

4 个答案:

答案 0 :(得分:20)

根据the MSDN documentation

  

要使转换成功,   必须实施IConvertible   界面,因为方法简单   打电话给合适的人   IConvertible方法。方法   需要将转换为    conversionType 受支持。

查看IConvertible界面,它有一个ToType方法。你可以试试吗,也许吧? (免责声明:我没有。这只是一个想法。)

修改:在您的情况下,您似乎希望将转换为string 转换为 a {{1} }。由于Foo类型(显然)未在其string实施中定义转换为Foo,因此我认为您运气不佳。


更新:我不想建议您应该如何处理此类问题,但是......

我在Reflector中查看了IConvertible的代码。它的长;我不会在这里重现它。但基本上它正如文档所说的那样:只有只有才能起作用:

  • Convert.ChangeType参数是实现value的类型的非null实例,或者:
  • IConvertible参数的类型和value参数是相同的(因此:conversionType也可以使用,但它很无用。)

然后,它会遍历Convert.ChangeType(myFoo, typeof(Foo))支持的所有类型(显然不包含任何用户定义的类型),并最终使用ToType作为后备。

因此,我们需要查看IConvertible类型string的实现。

可悲的是,这是一个不幸的路线:

ToType

return Convert.DefaultToType(this, type, provider); 做什么?与DefaultToType完全相同(减去ChangeType回退,显然是为了避免无限递归)。

所以这只是根本不起作用。

如果您完全依赖于在幕后使用ToType的第三方库,我建议您联系图书馆的开发人员并要求他们以某种方式扩展他们的API,这样您就可以完成任务'试图完成。一些可能性可能是:

  • 接受可选的Convert.ChangeTypeConverter<string, T>委托参数,如Ben Voigt在评论中所建议的那样。
  • 接受TypeConverter参数
  • 接受某种类型的参数,该参数实现了Func<string, T>
  • 等接口

无论如何,祝你好运。

答案 1 :(得分:5)

由于丹涛已经指出,直接从弦上施放不会起作用。你可以为字符串实现自己的包装并使用它吗?像

这样的东西
class MyString: IConvertible {

  public string Value { get; set; }

  ...
  object IConvertible.ToType(Type conversionType, IFormatProvider provider) {
    if (conversionType == typeof(Foo))
      return new Foo { Name = Value };
    throw new InvalidCastException();
  }

}
...
MyString myString = new MyString{Value="one"};
Foo myFoo = (Foo)Convert.ChangeType(myString, typeof(Foo));

不知道这是否是一个有用的想法,但无论如何..

答案 2 :(得分:1)

隐式运算符在这里不起作用?如果Foo是一个你可以修改的类,那么我过去曾经使用过类似的东西,这也允许你将Foo实例与一个字符串进行比较。

public class Foo
{
  public string Name { get; set; }

  public static implicit operator Foo(string value)
  {
    return new Foo { Name = value };
  }
}

...
Foo foo = "fooTest";
Console.WriteLine("Foo name: {0}", foo.Name);
...

编辑:如果您必须使用ChangeType,那么据我所知您运气不好。如果您可以修改API以使用TypeConverter,则可以使用以下内容。

...
Type type = typeof(Foo);
object value = "one";

var converter = TypeDescriptor.GetConverter(type);
if (converter.CanConvertFrom(value.GetType()))
{
  object newObject = converter.ConvertFrom(value);
  Console.WriteLine("Foo value: {0}", newObject.ToString());
}
...

public class FooConverter : TypeConverter
{
  public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  {
    return sourceType == typeof(string);
  }

  public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  {
    var name = value as string;
    if (name != null)
      return new Foo { Name = name };
    else
      return base.ConvertFrom(context, culture, value);
  }
}

[TypeConverter(typeof(FooConverter))]
public class Foo
{
  public string Name { get; set; }

  public override string ToString()
  {
    return Name;
  }
}

答案 3 :(得分:0)

  

对象value1 =“one”;

     

Foo value2 =(Foo)   System.Convert.ChangeType(value,typeof(Foo));

编辑:


那么,如果您尝试从字符串创建Foo类型,则可以使用反射:

String controlToCreate = "Foo";
Type typeofControl = Type.GetType(controlToCreate,true);