Вставить объект в коробку обратно в исходный тип
Я ожидаю, что один из двух ответов на это, либо невозможно, либо очень просто, и я упустил очевидный запрос 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; }
}
Очевидно, что это не будет компилироваться, так как на самом деле не существует способа для добавления в качестве переменной. Тем не менее, я надеюсь, что есть способ получить ссылку на фактический объект и тип, или, по крайней мере, способ динамического воссоздания типа.
Я ожидаю, что что-то простое, о чем я не замечаю, или лучший способ обойти его в целом. Дело в том, чтобы иметь возможность обернуть любой объект в контейнере и выяснить позже, что это было.
Ответы
Ответ 1
Идея состоит в том, чтобы определить истинный тип объекта в параметре метода
Это достаточно легко (и вы уже это делаете).
Type actualType = param.GetType();
Это даст вам конкретный конкретный тип объекта
а затем нарисуйте этот объект как истинный тип
Здесь все немного сходит с рельсов. Оператор литья в С# (использование которого - это то, что люди называют "кастинг" ), может сделать две вещи:
- Используйте явно выраженные преобразования типов для создания нового объекта, применяя преобразование к существующему объекту (обратите внимание, что это новая ссылка, которая создана, исходный тип объекта никогда не изменяется)
- Разрешить разработчику ссылаться на объект как тип, который находится на другом уровне в своей иерархии наследования, чем в настоящее время (или интерфейс, который реализован в типе, который ниже в иерархии, чем на данный момент ссылается)
В вашем случае первый вариант сразу; оператор литья, как и все операторы, не является полиморфным. То есть оператор применяется только в том случае, если он определен в типе, на который делается ссылка, а не на объект, на который ссылаются. Если вы хотите получить дополнительные разъяснения по этому поводу, дайте мне знать, но я не думаю, что это связано с вашим вопросом, поэтому я не буду вдаваться в него дальше, если не спросить.
Второй вариант - это единственный вариант, который может реально примениться к вам, но рассмотрите только две причины, которые вы хотели бы сделать:
- Чтобы вы могли ссылаться на объект как на конкретный конкретный тип, который находится на более низком уровне, чем в настоящее время (в вашем случае ваш объект имеет значение
object
, так что он почти такой же высокий)
- Чтобы вы могли ссылаться на объект как тип, который выше в иерархии, чтобы вы могли обойти скрытые (но не переопределенные) элементы.
(Подавляющее большинство бросков - причина № 1)
Причина, по которой вы хотите использовать любой из этих параметров, состоит в том, чтобы вы могли иметь строго типизированный объект и использовать различные члены, определенные для этого типа. Но все эти вещи применимы только к типам, которые вы знаете, когда пишете код. Не имеет смысла приводить к типу, который неизвестен во время компиляции, так как кастинг ничего не делает с фактическим объектом (он остается и остается его истинным типом, единственное, что меняется, это тип переменная, с которой вы ссылаетесь на объект).
Если вы можете предоставить более подробный пример того, что вы на самом деле пытаетесь сделать (в комплекте с кодом, как вы хотели бы или ожидали, что он будет работать), я мог бы предоставить что-то, смоделированное немного ближе к тому, что вы хотите, но, как он описал, это настолько специфично, насколько я могу получить.
Ответ 2
Прежде всего: это не "бокс". Бокс для типов значений, например struct
s.
Во-вторых: вам, возможно, понадобится:
- отражение времени компиляции, которое у С# не имеет
- Динамическое генерирование кода, которое вы можете сделать (больно) с помощью
Reflection.Emit
.
В-третьих: ваш пример кода variable1 as variable2
, что на самом деле не имеет смысла.:\Что вы намерены делать после этого? Возможно, там лучший способ.
Ответ 3
var actualType = boxed as originalType;
Просто чтобы мы оказались на одной странице, позвольте мне объяснить, почему это невозможно.
var
- это конструкция времени компиляции. Он идентичен объявлению переменной с правильным типом. Кроме того, что их проще вводить, его основное использование используется для анонимных типов, которые, как подразумевается, не имеют имен.
В любом случае, чтобы решить проблему с вашим вопросом, лучше всего использовать генерацию динамического кода либо с помощью Reflection.Emit
, либо CodeDom
(последнее гораздо легче понять, если вы не знаете ILASM, но намного медленнее).
В зависимости от того, что вы действительно хотите сделать, вы можете уйти с чем-то вроде
if(someObject is Container<Containee>) {
var container = (Container<Containee>)someObject;
//...
}
Но, если вы можете ожидать буквально любого типа, ну... удачи.
Ответ 4
Основная проблема заключается в том, что у меня есть общий объект передается через 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 ();
-
Перефразируйте свой вопрос и расширьте свой образец тем, как вы видите его работу после того, как вы сделали "магическое литье". Это даст нам представление о том, что вы пытаетесь выполнить.
Ответ 5
Вы можете использовать dynamic
:
dynamic actualType = boxed;
actualType.Entity.Property2 = "But I like this better.";
Это должно компилироваться и работать.