Вопрос
В настоящее время у меня есть этот тип кода:
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);
}
Некоторые идеи:
- Пусть оба типа наследуются от одного и того же типа, которые обладают общими свойствами
- Пусть оба типа реализуют один и тот же интерфейс, обладающий общими свойствами
- Используйте отражение для установки свойств, а не устанавливайте их напрямую (это, вероятно, более уродливо, чем того стоит)
- Используйте новый динамичный особенность, Я не пробовал это, но, похоже, это может решить вашу проблему
Вместо того чтобы пытаться выполнить приведение, возможно, вы могли бы попробовать задать свойства с помощью отражения.
Я динамически создаю объекты, используя отражение в приложении ASP.NET MVC.В основном я перечисляю свойства класса, нахожу соответствующее значение в хранилище данных и динамически преобразую значение и присваиваю его экземпляру объекта.Смотрите мой пост в блоге Динамическое приведение с помощью .NET