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

.NET: Как вы получаете Тип нулевого объекта?

У меня есть метод с параметром out, который пытается сделать преобразование типа. В основном:

public void GetParameterValue(out object destination)
{
    object paramVal = "I want to return this. could be any type, not just string.";

    destination = null; // default out param to null
    destination = Convert.ChangeType(paramVal, destination.GetType());
}

Проблема в том, что обычно кто-то называл бы это:

string output;
GetParameterValue(output);

Это не удастся из-за:

destination.GetType()

destination имеет значение null, поэтому мы не можем называть его .GetType(). Мы также не можем позвонить:

typeof(destination)

потому что назначение - это имя переменной, а не имя типа.

Итак, есть ли способ получить тип объекта, который имеет значение null? Я бы подумал, что должен был бы быть способ узнать, какой тип хранилища находится без того, что ему что-то назначено.


Чтобы дать немного больше информации, я пытаюсь сделать метод утилиты, который будет захватывать выходные параметры хранимой процедуры Oracle. Проблема в том, что DbParameter.Value имеет объект типа.

Что было бы идеальным для разработчиков, чтобы сделать что-то вроде:

string val = GetParameterValue("parameterName");

Примечательно то, что литейного типа нет. На практике вы не знаете lparam "equals", поэтому я пошел с:

string val;
GetParameterValue("parameterName", out val);

И фигурируя внутри метода, я бы знал тип назначения выходной переменной. Думаю, это было плохое предположение. В качестве альтернативы я также написал метод:

public T GetParameterValue<T>(string paramName)

Таким образом, разработчики могут:

string val = GetParameterValue<string>("parameterName");

Я обнаруживаю, что явное "строковое" объявление повторяется, тем более, что на практике место назначения, возможно, может иметь свойство объекта и тип данных оракула (подумайте об ORM):

MyObj.SomeProp = GetParameterValue<MyObj.SomeProp.GetType()>("parameterName");

Но опять же, если MyObj.SomeProp имеет значение null, вызов .GetType() завершается с ошибкой. VM должна знать тип MyObj.SomeProp, даже если его нулевой, правильно? или иначе, как он поймает исключения исключения?


Чтобы частично решить мою собственную проблему, я могу сделать:

MyObj.SomeProp = GetParameterValue<typeof(MyObj).GetField("SomeProp").GetType()>("parameterName");

Вся идея заключалась в том, чтобы не нужно явно использовать Type в нескольких местах, поэтому, если тип данных изменяется, его нужно изменить только в целевом объекте (MyObj.SomeProp) и в БД. Должен быть лучший способ...

4b9b3361

Ответ 1

Итак, есть ли способ получить тип объекта, который имеет значение null? Я бы подумал, что должен был бы быть способ узнать, какой тип хранилища находится без того, что ему что-то назначено.

Не обязательно. Лучшее, что вы можете сказать, это то, что это object. Ссылка null не указывает на какое-либо место хранения, поэтому нет метаданных, из которых он может сделать это определение.

Лучшее, что вы могли бы сделать, это изменить его на более общий, например:

public void GetParameterValue<T>(out T destination)
{
    object paramVal = "Blah";
    destination = default(T);
    destination = Convert.ChangeType(paramVal, typeof(T));
}

Тип T может быть выведен, поэтому вам не нужно явно указывать параметр типа.

Ответ 2

Это возможно, если вы не возражаете объявить свой метод как общий. Попробуйте это.

class Program
{
    public static void GetParameterValue<T>(out T destination)
    {
        Console.WriteLine("typeof(T)=" + typeof(T).Name);
        destination = default(T);
    }
    static void Main(string[] args)
    {
        string s;
        GetParameterValue(out s);
        int i;
        GetParameterValue(out i);
    }
}

Ответ 3

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

using System;

namespace MyNamespace
{
    public static class Extensions
    {
        /// <summary>
        /// Gets the declared type of the specified object.
        /// </summary>
        /// <typeparam name="T">The type of the object.</typeparam>
        /// <param name="obj">The object.</param>
        /// <returns>
        /// A <see cref="Type"/> object representing type 
        /// <typeparamref name="T"/>; i.e., the type of <paramref name="obj"/> 
        /// as it was declared. Note that the contents of 
        /// <paramref name="obj"/> are irrelevant; if <paramref name="obj"/> 
        /// contains an object whose class is derived from 
        /// <typeparamref name="T"/>, then <typeparamref name="T"/> is 
        /// returned, not the derived type.
        /// </returns>
        public static Type GetDeclaredType<T>(
            this T obj )
        {
            return typeof( T );
        }
    }
}

Так как это метод расширения, его аргумент может быть пустой ссылкой, и все следующие работы ОК:

string myString = "abc";
object myObj = myString;
Type myObjType = myObj.GetDeclaredType();

string myNullString = null;
object myNullObj = myNullString;
Type myNullObjType = myNullObj.GetDeclaredType();

Обратите внимание, что myObjType и myNullObjType оба будут установлены в System.Object, а не System.String.

Если вам действительно нужен тип содержимого obj, когда он не равен NULL, измените строку return на:

return (obj != null) ? obj.GetType() : typeof( T );

Ответ 4

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

public void GetParameterValue<T>(out T destination) { ... }

Ответ 5

Тип переменной назначения всегда System.Object. Вы можете просто вернуться

Convert.ChangeType(paramVal, System.Object).

Ответ 6

@Rally25s:

string val;
GetParameterValue("parameterName", out val);

Непонятно из вашего сообщения (в ответах), какая проблема с этим была. Если объявлено как:

void GetParameterValue<T>(string parameterName, out T val)  { }

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

T GetParameterValue<T>(string parameterName, T ununsed)  { }

Это будет выглядеть так:

MyObj.SomeProp = GetParameterValue("parameterName", MyObj.SomeProp);

который является скорее kludgey, но не хуже представленный метод.


Другой метод, который я использовал на С++, но еще не пробовавший в С#, должен иметь GetParameterValue() некоторый объект из вашего собственного дизайна, а затем реализовать для него несколько неявных операторов трансляции.

class ParameterHelper
{
   private object value;
   public ParameterHelper(object value)   { this.value = value;  }

   public static implicit operator int(ParameterHelper v)
     { return (int) v.value; }

}
ParameterHelper GetParameterValue( string parameterName);

MyObj.SomeProp = GetParameterValue("parameterName");

Ответ 7

В вашем примере это будет null от типа System.Object.

Скомпилирован ли ваш пример? Я получаю "не могу преобразовать из" out string "в ошибку" out object ".

Ответ 8

Я не думаю, что можно получить тип, когда значение равно null. Кроме того, поскольку вы вызываете внутри GetParameterValue, лучшее, что вы могли бы сделать (когда значение равно null), - это получить тип параметра "destination", который является "объектом". Вы можете рассмотреть возможность передачи Type в качестве параметра в GetParameterValue, где у вас есть дополнительная информация, например:

public void GetParameterValue(Type sourceType, out object destination) { //... }

Ответ 9

Если экземпляра нет, тип экземпляра отсутствует.

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


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

Ответ 10

На теоретическом уровне не нуль действительно такой же, как указатель на void в C, то есть он содержит адрес памяти и что он? Если это так, то это похоже на случай деления на ноль в математике, где результат undefined.

Для этой строки можно сделать следующее:

string val = GetParameterValue<string>("parameterName");

Просто удалите эту первую строку и теперь не повторение:

var val = GetParameterValue<string>("parameterName");

Не обязательно то, что вы ищете, хотя есть вопрос, как интерпретировать нуль?

Ответ 11

//**The working answer**

//**based on your discussion eheheheheeh**

public void s<T>(out T varName)
{
    if (typeof (T) == typeof(HtmlTable)) 
    { 
         //////////       
    }

}

protected void Page_Load(object sender, EventArgs e) 
{
    HtmlTable obj=null ;
    s(out obj);       
}

Ответ 12

http://msdn.microsoft.com/en-us/library/58918ffs.aspx

или

private Hashtable propertyTable = new Hashtable();

public void LoadPropertyTypes()
{
    Type t = this.GetType();

    System.Reflection.MemberInfo[] memberInfo = t.GetMembers();

    foreach (System.Reflection.MemberInfo mInfo in memberInfo)
    {
        string[] prop = mInfo.ToString().Split(Convert.ToChar(" "));
        propertyTable.Add(prop[1], prop[0]);
    }
}
public string GetMemberType(string propName)
{
    if (propertyTable.ContainsKey(propName))
    {
        return Convert.ToString(propertyTable[propName]);
    }
    else{
        return "N/A";
    }
}

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