Подтвердить что ты не робот

С#: динамическое время выполнения

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

dynamic Cast(object obj, Type castTo);

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

EDIT

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

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

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

dynamic d = source;

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

Ответ 2

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

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

Edit

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

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

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

Ответ 3

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

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;
}

Ответ 4

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

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

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

Ответ 5

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

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

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

Моя теория заключалась в том, что Newtonsoft мог бы сделать это, используя строковый посредник.

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

С#:

//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 < string, object > .

Ответ 6

Попробуйте общий:

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);

EDIT: 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 });
}

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

Ответ 7

Я знаю, что это действительно старый пост, но вот простое решение для работы с dynamic типом в c#.

  1. можно использовать простое отражение для перечисления прямых свойств
  2. или можете использовать метод расширения object
  3. или используйте GetAsOrDefault<int> чтобы получить новый строго типизированный объект со значением, если существует, или по умолчанию, если не существует.
    public static class DynamicHelper
{
    private static void Test( )
    {
        object myobj = new
                       {
                           myInt = 1,
                           myObjectArray = new object[ ]
                                           {
                                               "hello", "World"
                                           },
                           myStringArray = new string[ ]
                                           {
                                               "hello", "World"
                                           },
                           myIntArray = new[ ]
                                        {
                                            1, 2.3
                                        },
                           myDict = new
                                    {
                                        myInt = 1
                                    }
                       };

        var stringArray = myobj.GetAsArrayOrDefault< string >( d => d.myStringArray );
        var intArray = myobj.GetAsArrayOrDefault< string >( d => d.myIntArray );
        var myIntOrZero = myobj.GetAsOrDefault< int >( p => p.myInt );

        Console.WriteLine( $"stringArray: '{string.Join( ", ", stringArray )}'" );
        Console.WriteLine( $"stringArray: '{string.Join( ", ", intArray )}'" );
        Console.WriteLine( $"myIntOrZero: '{myIntOrZero}'" );
    }

    public static bool DoesPropertyExist( dynamic dyn, string property )
    {
        var t = ( Type )dyn.GetType( );
        var props = t.GetProperties( );
        return props.Any( p => p.Name.Equals( property ) );
    }

    public static TItem[ ] GetAsArrayOrDefault< TItem >( this object obj, Func< dynamic, object > test ) where TItem : class
    {
        try
        {
            var val = test( obj );
            if( val is IEnumerable o )
            {
                var l = new List< TItem >( );
                foreach( var i in o )
                    if( i is TItem item )
                        l.Add( item );

                return l.ToArray( );
            }
        }
        catch( RuntimeBinderException ) { }

        return default( TItem[ ] );
    }

    public static T GetAsOrDefault< T >( this object obj, Func< dynamic, T > test )
    {
        try
        {
            var val = test( obj );
            return ( T )val;
        }
        catch( RuntimeBinderException ) { }

        return default( T );
    }
}

Ответ 8

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

public static T Cast<T>(this dynamic obj) where T:class
{
   return obj as T;
}