C #: динамическое приведение во время выполнения - PullRequest
56 голосов
/ 07 февраля 2011

Я хотел бы реализовать метод со следующей подписью

dynamic Cast(object obj, Type castTo);

Кто-нибудь знает, как это сделать?obj определенно реализует castTo, но должен быть приведен правильно для того, чтобы сработали некоторые вещи связывания во время выполнения моего приложения.

Редактировать: Если некоторые ответы не имеют смысла, то это потому, что я изначально случайно набрал dynamic Cast(dynamic obj, Type castTo); - Я имею в виду, что ввод должен быть object или какой-то другой гарантированный базовый класс

Ответы [ 7 ]

80 голосов
/ 07 февраля 2011

Я думаю, что вы путаете вопросы каста и конвертации здесь.

  • Casting: изменение типа ссылки, указывающей на объект.Перемещение вверх или вниз по иерархии объектов или к реализованному интерфейсу
  • Преобразование: создание нового объекта из исходного исходного объекта другого типа и доступ к нему через ссылку на этот тип.

Часто трудно понять разницу между 2 в C #, потому что они оба используют один и тот же оператор C #: приведение.

В этой ситуации вы почти наверняка не ищете операцию приведения.Приведение dynamic к другому dynamic по сути является преобразованием личности.Он не предоставляет значения, потому что вы просто получаете ссылку dynamic на тот же базовый объект.Результирующий поиск не будет отличаться.

Вместо этого в этом сценарии вы хотите получить конверсию.Это превращает базовый объект в другой тип и обращается к результирующему объекту dynamic.Лучший API для этого - Convert.ChangeType.

public static dynamic Convert(dynamic source, Type dest) {
  return Convert.ChangeType(source, dest);
}

РЕДАКТИРОВАТЬ

Обновленный вопрос имеет следующую строку:

objопределенно реализует castTo

Если это так, то метод Cast не должен существовать.Источник object можно просто назначить для ссылки dynamic.

dynamic d = source;

Похоже, что вы пытаетесь достичь, чтобы увидеть определенный интерфейс или тип в иерархии sourceчерез dynamic ссылку.Это просто невозможно.Результирующая ссылка dynamic непосредственно увидит объект реализации.Он не просматривает какой-либо конкретный тип в иерархии источника.Таким образом, идея приведения к другому типу в иерархии, а затем обратно к dynamic точно идентична простому присвоению dynamic в первую очередь.Он по-прежнему будет указывать на тот же базовый объект.

28 голосов
/ 07 февраля 2011

Это должно работать:

public static dynamic Cast(dynamic obj, Type castTo)
{
    return Convert.ChangeType(obj, castTo);
}

Редактировать

Я написал следующий тестовый код:

var x = "123";
var y = Cast(x, typeof(int));
var z = y + 7;
var w = Cast(z, typeof(string)); // w == "130"

Он напоминает тип «приведения типов», который можно найти в таких языках, как PHP, JavaScript или Python (потому что он также преобразует значение в нужный тип). Я не знаю, хорошо ли это, но это, безусловно, работает ...: -)

8 голосов
/ 07 февраля 2011

Лучшее, что я получил до сих пор:

dynamic DynamicCast(object entity, Type to)
{
    var openCast = this.GetType().GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic);
    var closeCast = openCast.MakeGenericMethod(to);
    return closeCast.Invoke(entity, new[] { entity });
}
static T Cast<T>(object entity) where T : class
{
    return entity as T;
}
7 голосов
/ 04 мая 2011

Фреймворк с открытым исходным кодом Dynamitey имеет статический метод, который выполняет позднюю привязку с использованием DLR, включая преобразование приведения между другими .

dynamic Cast(object obj, Type castTo){
    return Dynamic.InvokeConvert(obj, castTo, explict:true);
}

Преимущество этого по сравнению с Cast<T>, называемым использованием отражения, заключается в том, что это также будет работать для любого IDynamicMetaObjectProvider, у которого есть операторы динамического преобразования, , т.е. Попробуйте перевести на DynamicObject.

6 голосов
/ 18 июля 2017

Я понимаю, что на это ответили, но я использовал другой подход и подумал, что стоит поделиться.Кроме того, я чувствую, что мой подход может привести к нежелательным накладным расходам.Тем не менее, я не могу наблюдать или рассчитывать что-либо, что так плохо под нагрузками, которые мы наблюдаем.Я искал какие-либо полезные отзывы об этом подходе.

Проблема работы с динамикой заключается в том, что вы не можете напрямую прикрепить какие-либо функции к динамическому объекту.Вы должны использовать что-то, что может выяснить назначения, которые вы не хотите вычислять каждый раз.

При планировании этого простого решения я смотрел, каковы действительные посредники при попытке повторно напечатать подобные объекты.Я обнаружил, что обычные подходы - это двоичный массив, строка (xml, json) или жесткое кодирование преобразования ( IConvertable ).Я не хочу вдаваться в двоичные преобразования из-за фактора поддерживаемости кода и лени.

Моя теория состояла в том, что Newtonsoft может сделать это с помощью строкового посредника.

Как недостаток, я вполне уверен, что при преобразовании строки в объект будет использоваться отражение путем поиска в текущей сборке объекта с совпадающими свойствами, создания типа, а затем создания экземпляров свойств, что потребует большего отражения.Если это правда, все это можно считать ненужными.

C #:

//This lives in a helper class
public static ConvertDynamic<T>(dynamic data)
{
     return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Newtonsoft.Json.JsonConvert.SerializeObject(data));
}

//Same helper, but in an extension class (public static class),
//but could be in a base class also.
public static ToModelList<T>(this List<dynamic> list)
{
    List<T> retList = new List<T>();
    foreach(dynamic d in list)
    {
        retList.Add(ConvertDynamic<T>(d));
    }
}

С учетом сказанного, это подходит для другой утилиты, которую я собрал, которая позволяет мне превращать любой объект вдинамичный.Я знаю, что мне пришлось использовать отражение, чтобы сделать это правильно:

public static dynamic ToDynamic(this object value)
{
    IDictionary<string, object> expando = new ExpandoObject();

    foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
        expando.Add(property.Name, property.GetValue(value));

    return expando as ExpandoObject;
}

Я должен был предложить эту функцию.Произвольный объект, назначенный динамически типизированной переменной, не может быть преобразован в IDictionary и нарушит функцию ConvertDynamic.Для использования этой цепочки функций необходимо предоставить динамику System.Dynamic.ExpandoObject или IDictionary.

1 голос
/ 07 февраля 2011

Попробуйте универсальный:

public static T CastTo<T>(this dynamic obj, bool safeCast) where T:class
{
   try
   {
      return (T)obj;
   }
   catch
   {
      if(safeCast) return null;
      else throw;
   }
}

Это формат метода расширения, поэтому его использование будет таким, как если бы он был членом динамических объектов:

dynamic myDynamic = new Something();
var typedObject = myDynamic.CastTo<Something>(false);

РЕДАКТИРОВАТЬ: Grr, не видел этого. Да, вы можете рефлексивно закрыть общий шаблон, и его будет не сложно спрятать в неуниверсальном методе расширения:

public static dynamic DynamicCastTo(this dynamic obj, Type castTo, bool safeCast)
{
   MethodInfo castMethod = this.GetType().GetMethod("CastTo").MakeGenericMethod(castTo);
   return castMethod.Invoke(null, new object[] { obj, safeCast });
}

Я просто не уверен, что вы получите от этого. По сути, вы берете динамику, вынуждаете приведение к отраженному типу, а затем вставляете его обратно в динамику. Может быть, вы правы, я не должен спрашивать. Но это, вероятно, будет делать то, что вы хотите. В основном, когда вы переходите в динамическую страну, вы теряете необходимость выполнять большинство операций приведения, поскольку вы можете узнать, что такое объект и что делает с помощью рефлексивных методов или методом проб и ошибок, поэтому не так много элегантных способов сделать это. *

0 голосов
/ 07 февраля 2011

В качестве альтернативы:

public static T Cast<T>(this dynamic obj) where T:class
{
   return obj as T;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...