2009-02-19 134 views
6

我现在有这种类型的代码:C#:铸造类型的动态

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    if (MainObject is SomeClassType1) 
    { 
     SomeClassType1 HelpObject = (SomeClassType1)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     SomeClassType2 HelpObject = (SomeClassType2)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
} 

假设SomeClassType1和SomeClassType2具有相同的组,我要分配(尽管它们可能在其他的不同)的特性,是有可能动态地将MainObject转换为适当的类型,然后赋值,而不重复代码? 这是我想看看到底是什么:

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type DynamicType = null; 

    if (MainObject is SomeClassType1) 
    { 
     DynamicType = typeof(SomeClassType1); 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     DynamicType = typeof(SomeClassType2); 
    } 

    DynamicType HelpObject = (DynamicType)MainObject; 
    HelpObject.Property1 = Arg1; 
    HelpObject.Property2 = Arg2; 
} 

很显然C#抱怨不能够找到DynamicType:

类型或命名空间名称“DynamicType”找不到(您是否缺少使用指令或程序集引用?)

在C#2.0中可能会这样吗?如果它比我现在的代码更混乱,比我认为这样做没有意义,但我很有兴趣了解。谢谢!

编辑:只是为了澄清,我完全理解,实现一个接口是最合适的,可能是正确的解决方案。也就是说,我更感兴趣的是如何在没有实现接口的情况下做到这一点。感谢您的好评!

回答

15

它看起来像你关心的两种类型实现相同的两个属性。在这种情况下,你想要做的就是定义一个接口这些属性:

public interface IMyInterface 
{ 
    public Foo Property1 {get; set;} 
    public Bar Property2 {get;set;} 
} 

然后,确保每个类的告诉他们实现新的界面编译器。最后,使用一个通用的方法与被约束到interace类型参数:

private void FillObject<T>(T MainObject, Foo Arg1, Bar Arg2) 
    where T : IMyInterface 
{ 
    MainObject.Property1 = Arg1; 
    MainObject.Property2 = Arg2; 
} 

注意,即使有额外的代码申报的接口,这些片段最终仍小于或者您发布的片段之一在问题中,如果您关心的类型数量增加,则此代码更容易扩展。

9

基本上你在这里做的是根据对象的类型写一个switch语句。除了你的第一个例子(这在最好的情况下是单调乏味的),没有什么内在的好方法可以做到这一点。

我写了一个小型框架来切换类型,使语法更简洁一些。它允许你编写如下代码。

TypeSwitch.Do(
    sender, 
    TypeSwitch.Case<Button>(
     () => textBox1.Text = "Hit a Button"), 
    TypeSwitch.Case<CheckBox>(
     x => textBox1.Text = "Checkbox is " + x.Checked), 
    TypeSwitch.Default(
     () => textBox1.Text = "Not sure what is hovered over")); 

博客文章:http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx

2

,而不是试图投,或许你可以尝试设置使用反射性能。

4
private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type t = MainObject.GetType(); 

    t.GetProperty("Property1").SetValue(MainObject, Arg1, null); 
    t.GetProperty("Property2").SetValue(MainObject, Arg2, null); 
} 
+0

我认为这里的泛型更合适,但至少我会检查以确保属性存在第一。 – 2009-02-19 18:25:47

+0

我只是想展示你用反射的方式。对于这个问题,这不是*完整*或*推荐*方法。 – 2009-02-19 18:28:04

+0

我觉得这个灾难已经写满了...... – 2009-02-19 18:29:45

7

你能修改SomeClassType1,SomeClassType2等吗?如果是,那么我会建议你创建一个包含你的公共属性的接口,然后在FillObject()内对该接口进行类型转换来设置属性。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace SO566510 
{ 
    interface IMyProperties 
    { 
     int Property1 { get; set; } 
     int Property2 { get; set; } 
    } 

    class SomeClassType1 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 

    class SomeClassType2 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var obj1 = new SomeClassType1(); 
      var obj2 = new SomeClassType2(); 

      FillObject(obj1, 10, 20); 
      FillObject(obj2, 30, 40); 

     } 

     private static void FillObject(IMyProperties objWithMyProperties 
            , int arg1, int arg2) 
     { 
      objWithMyProperties.Property1 = arg1; 
      objWithMyProperties.Property2 = arg2; 
     } 
    } 
} 
3

一些想法:

  1. 有两种类型的从具有公共属性的相同类型继承
  2. 有两种实现一个具有公共属性
  3. 使用反射来设置属性相同的接口而不是直接设置它们(这可能比它的价值更难看)
  4. 使用新的dynamic feature,我没有试过这个,但看起来像它可能会解决您的问题
0

我在ASP.NET MVC应用程序中使用反射动态地转换对象。基本上我枚举类的属性,在数据存储中找到相应的值并动态地转换该值并将其分配给对象实例。看我的博客文章 Dynamic Casting with .NET