C #: как выполнить операцию «как» с типом - PullRequest
8 голосов
/ 21 сентября 2011

Я хочу проверить, может ли данный object быть приведен к данному Type.

В этом сценарии у меня есть объект, и Type представляет тип, к которому я хочу привести его:

public function FooBar(..., object data, Type expected) {
    ...
    var unboxedData = ?
    if (unboxedData == null) {
       ....
    }
    ...
}

Как я могу привести data к типу type представляет?

По сути, я хочу сделать это:

    var unboxedData = data as Type;

... но, конечно, вы не можете использовать Type с оператором as, так чтомне делать?

Ответы [ 6 ]

6 голосов
/ 21 сентября 2011

Редактировать 2: Я скажу, что это невозможно без размышлений или обобщений.С помощью отражения у вас нет проверки во время компиляции, и вы должны использовать отражение (или dynamic) для дальнейшего вызова методов / свойств объекта.С дженериками вы не можете использовать объект Type, чтобы добраться туда один.Сделайте ваш выбор.Можно ли реорганизовать ваш вызывающий код, чтобы разрешить генерики?


Если это разрешено, это может быть проще обработано универсальным методом:

public resultType FooBar<T>(..., object data) {
    ...
    T unboxedData = (T)data;
    ...
}

Редактировать: Кроме того, вы можете использовать data as T, если включите ограничение общего типа where T : class:

public something FooBar<T>(..., object data)
    where T : class
{
    ...
    T unboxedData = data as T;
    if (unboxedData == null) {
        ...
    }
    ...
}
3 голосов
/ 21 сентября 2011

... но, конечно, вы не можете использовать Type с утверждением as, так что мне делать?

Morre важно, вы не можете использовать var thisпуть.Так что здесь нечего приобретать.

Вы можете проверить , если это правильный тип с помощью

 if (expected.IsInstanceOfType(data))

Но тогда вы все равно не сможете написать какой-либо приличный код для доступа к свойствам или методам data,

2 голосов
/ 21 сентября 2011

C # предоставляет ключевое слово as для быстрого определить во время выполнения, совместим ли данный тип с другим. Когда вы используете ключевое слово as, вы можете определить совместимость, проверив нулевое возвращаемое значение. Учтите следующее:

Hexagon hex2 = frank as Hexagon;

if (hex2 == null)
    Console.WriteLine("Sorry, frank is not a Hexagon...");

В дополнение к ключевому слову as язык C # предоставляет ключевое слово is для определения совместимости двух элементов. Однако, в отличие от ключевого слова as, ключевое слово is возвращает false, а не нулевую ссылку, если типы несовместимы.

if (emp is SalesPerson)
{
    Console.WriteLine("{0} made {1} sale(s)!", emp.Name, 
                                              ((SalesPerson)emp).SalesNumber);
}
1 голос
/ 22 сентября 2011

Это довольно сложно.Проблема в том, что var не означает «вариант».Это действует больше как временный заполнитель, который C # заполняет фактическим типом, как только информация о типе может быть выведена из выражения.unboxedData все еще очень сильно типизированная переменная.Просто компилятор пытается выяснить тип, а не явно указывать его.Крайне важно отметить, что типизация по-прежнему происходит во время компиляции, а не во время выполнения.

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

Ваши параметры ограничены одним из двух возможных объявлений:

  • объект
  • динамический

На основео том, что я думаю , что вы хотите сделать с unboxedData Я подозреваю, dynamic - это маршрут, по которому вы хотите идти, потому что он позволит вам вызывать любой метод для цели Type.

Итак, вот что я придумал.

public void FooBar(object value, Type expected)
{
  dynamic unboxedData = expected.FromObject(value);
  unboxedData.CallSomeMethodDefinedInTheTargetType(); // This will work.
}

Для этого требуется следующий метод расширения.

public static class TypeExtension
{
    public static object FromObject(this Type target, object value)
    {
        var convertable = value as IConvertible;
        if (convertable != null)
        {
            return convertable.ToType(target, null);
        }
        Type type = value.GetType();
        if (target.IsAssignableFrom(type))
        {
            return value;
        }
        MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
        foreach (MethodInfo mi in methods)
        {
            if (mi.ReturnType == target)
            {
                try
                {
                    return mi.Invoke(null, new object[] { value });
                }
                catch (TargetInvocationException caught)
                {
                    if (caught.InnerException != null)
                    {
                        throw caught.InnerException;
                    }
                    throw;
                }
            }
        }
        throw new InvalidCastException();
    }
}

Приведение будет работать, если выполнено одно из следующих действий.

  • Преобразуемое значение реализует IConvertible и имеет путь преобразования к целевому типу.
  • Преобразуемое значение подклассов целевого типа.
  • Значениебыть преобразованным определяет явное преобразованиеator в объявлении класса.
1 голос
/ 21 сентября 2011
if (data.GetType() == t || data.GetType().IsSubclassOf(t))
{
//do your thing
}

Должен сказать вам, является ли он точным или подклассом (чтобы его можно было привести к нему).

0 голосов
/ 22 сентября 2011

Ну, озираясь, я нашел что-то ... Как проверить, существует ли явное или явное приведение?

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

    static bool isConvertableTo(object o, Type t)
    {
        try
        {
            var expr = Expression.Constant(o);
            var res = Expression.Convert(expr, t);
            return true;
        }
        catch { }
        return false;
    }

Другая полезная ссылка с тем же подходом: Проверка, поддерживает ли тип неявное или явное преобразование типа в другой тип с помощью .NET

...