.NET:如何获得null对象的Type?

时间:2008-10-31 18:33:18

标签: c# .net types gettype

我有一个带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()

目的地为空,因此我们无法在其上调用.GetType()。我们也不能打电话:

typeof(destination)

因为destination是变量名而不是类型名。

那么有没有办法获得设置为null的对象的类型?我认为必须有一种方法可以知道存储位置的类型,而不会分配任何东西。


为了提供更多信息,我试图创建一个实用程序方法来获取Oracle存储过程的输出参数。问题是DbParameter.Value是object类型。

对于开发人员来说,理想的做法是:

string val = GetParameterValue("parameterName");

值得注意的是,没有类型的铸造。在实践中,你不知道“等于”的lparam,所以我选择了:

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

在方法中,我会知道输出变量的目标类型。我猜这是一个不好的假设。作为替代方案,我也写了这个方法:

public T GetParameterValue<T>(string paramName)

所以开发人员可以这样做:

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

我发现显式“字符串”声明是重复的,特别是因为在实践中,目标可能是对象属性和oracle数据类型可能会改变(想想ORM):

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

但是,如果MyObj.SomeProp为null,则.GetType()调用失败。 VM必须知道MyObj.SomeProp的类型,即使它为null,对吗?或者它会如何捕获强制转换异常?


要部分解决我自己的问题,我可以这样做:

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

整个想法是不必在多个位置显式使用Type,因此如果数据类型发生更改,则只需在目标对象(MyObj.SomeProp)和数据库中进行更改。必须有一个更好的方法...

12 个答案:

答案 0 :(得分:32)

  

那么有没有办法获得设置为null的对象的类型?我认为必须有一种方法可以知道存储位置的类型,而不会分配任何东西。

不一定。你能说的最好的是objectnull引用不指向任何存储位置,因此没有元数据可以从中进行确定。

您可以做的最好的事情是将其更改为更通用,例如:

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

可以推断出T的类型,因此您不需要明确地为方法提供类型参数。

答案 1 :(得分:8)

如果您不介意将方法声明为通用方法,则可能会这样做。试试这个。

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

答案 2 :(得分:7)

以下扩展方法返回其声明的参数类型,无论其内容如何:

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

请注意,myObjTypemyNullObjType都将设置为System.Object,而不是System.String。

如果您确实想要obj的内容类型而不是null,那么将return行更改为:

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

答案 3 :(得分:3)

目前您无法知道传递给方法的内容。您可以将其转换为通用方法。像这样:

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

答案 4 :(得分:2)

目标变量的类型始终为System.Object。你可以回来

Convert.ChangeType(paramVal, System.Object).

答案 5 :(得分:1)

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

这是相当笨拙的,但不是更差的方法。


我在C ++中使用但在C#中尚未尝试过的另一种方法是让GetParameterValue()成为你自己设计的一些对象,然后为它实现一些隐式的转换操作符。 / p>

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

答案 6 :(得分:0)

在您的示例中,它将为System.Object类型的null。

你的例子甚至可以编译吗?我得到一个“无法从'输出字符串'转换为'输出对象'”错误。

答案 7 :(得分:0)

我不认为当值为null时可以获取类型。此外,由于您在GetParameterValue内部进行调用,因此您可以做的最好(当值为null时)是获取“目标”参数的类型,即“对象”。您可能考虑将Type作为参数传递给GetParameterValue,您可以在其中获取更多信息,例如:

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

答案 8 :(得分:0)

如果没有实例,则没有实例类型。

您可以做的最好的事情是使用引用的类型,这意味着如果您有一个对象引用(如问题中的方法),引用类型就是对象。


您可能不应该尝试将一种类型的null实例转换为另一种类型的null实例...

答案 9 :(得分:0)

在理论级别上,null与C中的void指针实际上不一样,也就是说它保存了一个内存地址,就是这样吗?如果是这样,那么它类似于数学中除零的情况,其结果是未定义的。

可以为此行执行以下操作:

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

删除第一个字符串,现在没有重复:

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

不一定是你在寻找什么,虽然有一个问题是如何解释null?

答案 10 :(得分:0)

//**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);       
}

答案 11 :(得分:-1)

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

以这种方式我们可以使用switch来管理不同的属性类型。