Приведение коробочного объекта обратно к исходному типу
Я ожидаю, что есть один из двух ответов на этот вопрос, либо невозможный, либо чрезвычайно простой, и я пропустил очевидный запрос Google.
Основная проблема заключается в том, что у меня есть универсальный объект, передаваемый черезEventHandler
, который блокирует объект и запутывает истинный тип; только во время выполнения я знаю, что это за объект.
По общему признанию, ключевое слово dynamic
может обойти проблему, но я хотел бы не потерять IntelliSense и все остальное, если я могу избежать этого. К тому же, это не решает проблемы нет знание того, каково каждое из свойств родового объекта, не требует большого количества размышлений.
EDIT: идея состоит в том, чтобы иметь возможность определить истинный тип объекта в параметре метода, а затем привести этот объект как истинный тип, не зная его заранее. Это всего лишь упрощенный пример. Возможно, слово "бокс" было неверным.
Пример:
public class Program
{
static void Main(string[] args)
{
var container = new Container<Containee>(
new Containee
{
Property1 = Guid.NewGuid(),
Property2 = "I'm a property!",
Property3 = DateTime.Now
}
);
var boxed = (object)container;
var originalType = boxed.GetType();
// DOES NOT COMPILE: would like an operation like this
// EDIT: Request for more detail
var actualType = boxed as originalType;
actualType.Entity.Property2 = "But I like this better.";
}
}
public class Containee
{
public Guid Property1 { get; set; }
public string Property2 { get; set; }
public DateTime Property3 { get; set; }
}
public class Container<T>
{
public Container(T entity)
{
Entity = entity;
}
public T Entity { get; internal set; }
}
Очевидно, что это не будет компилироваться, так как на самом деле нет способа привести в качестве переменной. Тем не менее, я надеюсь существует способ получить ссылку на фактический объект и тип или, по крайней мере, способ динамического повторного создания типа.
Я ожидаю, что есть что-то простое, что я упускаю из виду, или лучший способ обойти это в целом. Суть в том, чтобы иметь возможность завернуть любой предмет в контейнер и выяснить позже, что это было.5 ответов:
Это достаточно просто (и вы уже делаете это).Идея заключается в том, чтобы определить истинный тип объекта в параметре метода
Type actualType = param.GetType();
Это даст вам фактический конкретный тип объекта
И затем приведите этот объект как истинный Тип
Вот тут-то все и выходит из-под контроля. Оператор кастинга в C# (использование которого люди называют "кастингом") может делать две вещи:
- использование специфические для типа явные преобразования для создания нового объекта путем применения преобразования к существующему объекту (обратите внимание, что это Новая ссылка, которая создается; тип исходного объекта никогда не изменяется)
- разрешить разработчику ссылаться на объект как на тип, находящийся на другом уровне иерархии наследования, чем тот, который предоставлен в данный момент (или интерфейс, реализованный на типе, который находится ниже в иерархии, чем тот, на который имеется ссылка в данный момент)
В в вашем случае первый вариант является правильным; оператор кастинга, как и все операторы, не является полиморфным. То есть оператор применяется только в том случае, если он определен для типа , на который ссылаются, а не для объекта , на который ссылаются. Если вы хотите получить дополнительные разъяснения по этому вопросу, дайте мне знать, но я не думаю, что это имеет отношение к вашему вопросу, поэтому я не буду вдаваться в него дальше, если меня не спросят.
Второй вариант является единственным вариантом, который может реально применяться для вас, но рассмотрим только две причины, по которым вы хотели бы это сделать:
- Таким образом, вы можете ссылаться на объект как на конкретный конкретный тип, который находится на более низком уровне, чем в настоящее время (в вашем случае ваш объект является
object
, так что это почти так же высоко, как он идет)- , чтобы можно было ссылаться на объект как на тип, который выше в иерархии, чтобы можно было обойти скрытые (но не переопределенные) члены.
(подавляющее большинство слепков являются по причине №1)
Причина, по которой вы хотите использовать любой из этих параметров, заключается в том, что вы можете иметь строго типизированный объект и использовать различные члены, определенные для этого типа. Но все эти вещи применимы только к типам, которые Вызнаете , Когда пишете код. Нет смысла приводить к типу, который неизвестен во время компиляции, так как приведение ничего не делает с реальным объектом (он является и должен оставаться его истинным типом; единственное, что изменяется-это тип объекта). переменная , С помощью которой вы ссылаетесь на объект).
Если вы можете предоставить более подробный пример того, что вы на самом деле пытаетесь сделать (в комплекте с кодом, как вы хотите или ожидаете, что он будет работать), я мог бы предоставить что-то смоделированное немного ближе к тому, что вы хотите, но поскольку это описано, это настолько конкретно, насколько я могу получить.
Прежде всего: это не "бокс". Бокс предназначен для типов значений, таких как
struct
s.Во-вторых: то, что вам, вероятно, нужно, это либо:
В-третьих: ваш пример кода делает
- отражение во время компиляции, которого в C# нет
- динамическая генерация кода, которую вы можете сделать (болезненно) с
Reflection.Emit
.variable1 as variable2
, что на самом деле не имеет смысла. - Что ты собираешься делать после этого? Возможно, есть лучший способ.
Просто чтобы мы были на одной странице, позвольте мне объяснить, почему это невозможно.var actualType = boxed as originalType;
В любом случае, чтобы добраться до сути вашего вопроса, лучше всего использовать динамическую генерацию кода, либо с
var
это конструкция времени компиляции. Это тождественно прямому объявлению переменной с соответствующим типом. Помимо того, что его легче печатать, он в основном используется для анонимных типов, которые, как подразумевается, не имеют имен.Reflection.Emit
, либо сCodeDom
(последнее гораздо легче понять, если вы этого не делаете знаю ИЛАЗМ, но гораздо медленнее).В зависимости от того, что вы на самом деле хотите сделать, вам может сойти с рук что-то вроде
Но, если вы можете ожидать буквально любого типа, хорошо... удачи.if(someObject is Container<Containee>) { var container = (Container<Containee>)someObject; //... }
Основная проблема заключается в том, что у меня есть универсальный объект, передаваемый через EventHandler, который помещает объект и запутывает истинный тип; только при я не знаю, что это за объект.
Как вы хотите обрабатывать его, если тип известен только во время выполнения? Вы не можете вызвать какие-либо конкретные методы класса, потому что вы не будете знать точный тип в любом случае, если все объекты не разделяют некоторый набор методов, которые могут быть извлечены в качестве интерфейса.
В принципе, у вас есть несколько вариантов:
Используйте
is
и делайте разные вещи для разных типов:object value = GetValue (); if (value is Program) ((Program)value).Run (); else if (value is Animal) ((Animal)value).Run ();
Если предполагается, что все возможные типы совместно используют набор операций, используйте интерфейс:
object value = GetValue (); IRunnable runnable = (IRunnable)value; runnable.Run ();
Перефразируйте свой вопрос и расширьте свой образец с тем, как вы видите, что он работает после того, как вы сделали "магический кастинг". Это даст нам представление о том, чего вы пытаетесь достичь.