Приведение коробочного объекта обратно к исходному типу
Я ожидаю, что есть один из двух ответов на этот вопрос, либо невозможный, либо чрезвычайно простой, и я пропустил очевидный запрос 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)
Причина, по которой вы хотите использовать любой из этих параметров, заключается в том, что вы можете иметь строго типизированный объект и использовать различные члены, определенные для этого типа. Но все эти вещи применимы только к типам, которые Вызнаете , Когда пишете код. Нет смысла приводить к типу, который неизвестен во время компиляции, так как приведение ничего не делает с реальным объектом (он является и должен оставаться его истинным типом; единственное, что изменяется-это тип объекта). переменная , С помощью которой вы ссылаетесь на объект).
Если вы можете предоставить более подробный пример того, что вы на самом деле пытаетесь сделать (в комплекте с кодом, как вы хотите или ожидаете, что он будет работать), я мог бы предоставить что-то смоделированное немного ближе к тому, что вы хотите, но поскольку это описано, это настолько конкретно, насколько я могу получить.
Прежде всего: это не "бокс". Бокс предназначен для типов значений, таких как
structs.Во-вторых: то, что вам, вероятно, нужно, это либо:
В-третьих: ваш пример кода делает
- отражение во время компиляции, которого в 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 ();Перефразируйте свой вопрос и расширьте свой образец с тем, как вы видите, что он работает после того, как вы сделали "магический кастинг". Это даст нам представление о том, чего вы пытаетесь достичь.