.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
) и в БД. Должен быть лучший способ...
Ответы
Ответ 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";
}
}
таким образом мы можем использовать переключатель для управления различными типами свойств.