Вопрос

В настоящее время у меня есть этот тип кода:

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

Предполагая, что someclassstype1 и someclassstype2 имеют один и тот же набор свойств, которые я хочу присвоить (хотя они могут отличаться другими), возможно ли динамически привести 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' (вам не хватает директивы using или ссылки на сборку?)

Возможно ли что-то подобное в C # 2.0?Если это более запутанно, чем мой текущий код, то я не вижу смысла в этом, но мне очень интересно это выяснить.Спасибо!

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

Это было полезно?

Решение

Похоже, что оба типа, о которых вы заботитесь, реализуют одни и те же два свойства.В этом случае то, что вы хотите сделать, это определить интерфейс для этих свойств:

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

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

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

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

Другие советы

По сути, то, что вы здесь делаете, - это написание инструкции 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

Сможете ли вы внести изменения в someclassstype1, someclassstype2 и т.д.?Если да, то я предложу вам создать интерфейс, содержащий ваши общие свойства, а затем привести тип к этому интерфейсу внутри 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;
        }
    }
}
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);
}

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top