2009-02-19 4 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? Если это более грязно, чем мой текущий код, я не вижу смысла в этом, но мне очень интересно узнать. Благодаря!

EDIT: Просто для пояснения, я прекрасно понимаю, что реализация интерфейса является наиболее подходящим и, вероятно, правильным решением. Тем не менее, меня больше интересует, как я мог это сделать без реализации интерфейса. Спасибо за отличные ответы!

ответ

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; 
} 

Обратите внимание, что даже с дополнительным кодом, чтобы объявить интерфейс, эти фрагменты до сих пор в конечном итоге короче ни один из фрагментов вы вывесили в вопросе, и этот код намного проще расширить, если количество типов, о которых вы заботитесь, увеличивается.

+1

+1 Ницца ... Я бы не подумал использовать дженерики, я бы просто бросил в интерфейс. –

+0

Как полезен здесь общий параметр T? Почему бы просто не использовать FillObject (главный объект IMyInterface, ...)? –

+0

Мне любопытно - почему вы использовали дженерики в этом случае, а не только private void FillObject (IMyInterface MainObject, Foo Arg1, Bar 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

Я думаю, что дженерики более уместны здесь, но, по крайней мере, я бы проверял, чтобы убедиться, что свойства существуют в первую очередь. –

+0

Я просто хотел продемонстрировать, как вы это делаете с отражением. Это не * полный * или * рекомендованный * подход для этой проблемы. –

+0

Я думаю, что это катастрофа написана по всему этому ... –

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; 
     } 
    } 
} 
+0

Хотя это, безусловно, вариант, это будет излишним для простой вещи, которую я пытаюсь достичь. Мой код в основном то, что я написал выше, только с несколькими типами и именами var изменены. –

+0

Я собирался предложить то же самое. Если они имеют одинаковые общедоступные свойства, интерфейс кажется уместным. –

+0

@MK_Dev: Это не так много работы, как вы думаете, вам нужно попробовать. На самом деле это может привести к уменьшению размера вашего кода. –

3

Некоторые идеи:

  1. оба типа наследуют от того же типа, которые имеют общие свойства
  2. оба типа реализуют одинаковый интерфейс, которые имеют общие свойства
  3. Использование отражения для задания свойств вместо того, чтобы устанавливать их напрямую (это, вероятно, более уродливое, чем это стоит)
  4. Использовать новый dynamic feature, я не пробовал, но похоже, что он может решить вашу проблему.
0

Я динамически бросаю объекты, используя Reflection в приложении ASP.NET MVC. В основном я перечисляю свойства класса, нахожу соответствующее значение в хранилище данных и динамически отбрасываю значение и присваиваю его экземпляру объекта. См. Мой пост в блоге Dynamic Casting with .NET

Смежные вопросы