Вставить объект в коробку обратно в исходный тип

Я ожидаю, что один из двух ответов на это, либо невозможно, либо очень просто, и я упустил очевидный запрос 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.";

Это должно компилироваться и работать.