2008-10-31 41 views
26

Tôi có một phương thức có tham số ngoài cố gắng thực hiện chuyển đổi loại. Về cơ bản:.NET: Làm thế nào để bạn có được kiểu của một đối tượng null?

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

Vấn đề là thường ai đó sẽ gọi đây như:

string output; 
GetParameterValue(output); 

này sẽ thất bại vì:

destination.GetType() 

đích là null, vì vậy chúng tôi không thể gọi .GetType() trên đó. Chúng tôi cũng không thể gọi:

typeof(destination) 

vì đích là tên biến không phải là tên loại.

Vì vậy, có cách nào để nhận loại đối tượng được đặt thành không? Tôi nghĩ rằng sẽ có một cách để biết loại vị trí lưu trữ là gì mà không có nó được gán bất cứ điều gì.


Chỉ cần cung cấp thêm một chút thông tin, tôi đang cố tạo phương thức tiện ích sẽ lấy thông số đầu ra của thủ tục được lưu trữ của Oracle. Vấn đề là DbParameter.Value thuộc loại đối tượng.

Điều gì sẽ là lý tưởng sẽ cho các nhà phát triển để làm một cái gì đó như:

string val = GetParameterValue("parameterName"); 

Điều đáng chú ý là không có đúc các loại. Trong thực tế, bạn không biết lparam của "bằng", vì vậy tôi đã đi với:

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

Và được tìm trong phương pháp, tôi sẽ biết loại đích của biến đầu ra. Tôi đoán đó là một giả định tồi tệ. Là một thay thế, tôi cũng đã viết phương pháp:

public T GetParameterValue<T>(string paramName) 

Vì vậy, các nhà phát triển có thể làm:

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

Tôi thấy rõ ràng "chuỗi" khai được lặp đi lặp lại, đặc biệt là vì trong thực tế, đích nếu có thể là một tài sản đối tượng và kiểu dữ liệu oracle có thể thay đổi (nghĩ ORM):

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

Nhưng một lần nữa, nếu MyObj.SomeProp là null, mà .GetType() cuộc gọi không thành. VM phải biết loại MyObj.SomeProp, ngay cả khi nó rỗng, phải không? hoặc người nào khác sẽ bắt được ngoại lệ?


Để giải quyết một phần vấn đề của riêng tôi, tôi có thể làm:

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

Toàn bộ ý tưởng là để không phải sử dụng một cách rõ ràng Gõ vào nhiều hơn một nơi, do đó nếu những thay đổi kiểu dữ liệu , nó chỉ phải được thay đổi trong đối tượng đích (MyObj.SomeProp) và trong DB. Phải có cách tốt hơn ...

Trả lời

29

Vậy có cách nào để nhận được các loại của một đối tượng được thiết lập để null? Tôi nghĩ rằng sẽ có một cách để biết loại vị trí lưu trữ là gì mà không có nó được gán bất cứ điều gì.

Không nhất thiết. Điều tốt nhất bạn có thể nói là nó là object. Tham chiếu null không trỏ đến bất kỳ vị trí lưu trữ nào, do đó không có siêu dữ liệu mà từ đó nó có thể đưa ra quyết định đó.

Điều tốt nhất mà bạn có thể làm là thay đổi nó để được chung chung hơn, như trong:

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

Loại T có thể được suy ra, vì vậy bạn không cần phải cung cấp cho một tham số kiểu để phương pháp này một cách rõ ràng.

+0

Đề nghị tốt! Đối số thứ hai phải là typeof (T) và không phải typeof (T) .GetType(). – Hallgrim

+0

không may rằng mã "out T dest" không biên dịch vì nó không thể tìm thấy loại "T". Tôi sẽ nghiên cứu tùy chọn này nhiều hơn một chút ... – CodingWithSpike

+0

@ rally25rs: T là một loại chung, trong trường hợp này những gì đang được gợi ý là bạn sử dụng Generics để xác định loại phương pháp. –

0

Trong ví dụ của bạn, nó sẽ là không có loại System.Object.

Ví dụ của bạn có biên dịch không? Tôi nhận được một "không thể chuyển đổi từ 'ra chuỗi' để 'ra đối tượng'" lỗi.

+0

kiểm tra đơn vị của tôi cho nó đã biên dịch, nhưng tôi đã có bộ biến thực tế ra một đối tượng không phải là một chuỗi. – CodingWithSpike

2

Loại biến đích của bạn luôn là System.Object. Bạn chỉ có thể trả lại

Convert.ChangeType(paramVal, System.Object). 
3

Hiện tại bạn không có cách nào biết được những gì được chuyển vào phương pháp. Bạn có thể chuyển đổi nó thành một phương pháp chung. Như thế này:

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

+0

Tôi thực sự đã làm phương pháp này giống như một cách thứ 2 để nhận được cùng một dữ liệu. Nó đã được làm việc, vì vậy tôi đã không bao gồm nó trong bài viết của tôi :) – CodingWithSpike

0

Tôi không nghĩ rằng có thể lấy loại khi giá trị là rỗng. Ngoài ra, vì bạn đang gọi bên trong GetParameterValue, tốt nhất bạn có thể làm (khi giá trị là null) là lấy kiểu tham số "đích" là "đối tượng". Bạn có thể xem xét thông qua Type như một tham số để GetParameterValue, nơi bạn có thêm thông tin, chẳng hạn như:

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

Có thể nếu bạn không nhớ tuyên bố phương pháp của bạn như một generic. Thử cái này.

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

Nếu không có trường hợp nào, không có loại cá thể nào.

Điều tốt nhất bạn có thể làm là sử dụng loại tham chiếu, có nghĩa là nếu bạn có tham chiếu đối tượng (như trong phương thức trong câu hỏi), kiểu tham chiếu là đối tượng.


Bạn có lẽ không cần phải cố gắng để chuyển đổi một trường hợp vô của một loại vào một trường hợp vô loại khác ...

1

@ Rally25s:

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

Đó là chưa rõ ràng từ bạn tin nhắn (trong câu trả lời) vấn đề với cái đó là gì. Nếu được khai báo là:

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

Hơn cuộc gọi, như bạn đã viết ở trên, sẽ hoạt động (bạn không cần chỉ định loại). Tôi đoán rằng đã không làm việc cho bạn bởi vì bạn không thể sử dụng một tài sản như là một tham số "out".Các con đường xung quanh đó là sử dụng cả hai phương pháp:

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

này sẽ được gọi là như thế này:

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

mà là khá kludgey, nhưng không phải là phương pháp tồi tệ hơn trình bày.


Một phương pháp khác nhau, mà tôi đã sử dụng trong C++, nhưng đã không cố gắng nhưng trong C#, là phải có GetParameterValue() một số đối tượng của bạn sở hữu thiết kế, và sau đó thực hiện một số nhà khai thác diễn viên tiềm ẩn cho nó.

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

Marcus đã chỉnh sửa câu trả lời của mình sau khi tôi đọc nó. Ban đầu, ông đã có "GetParameterValue (ra T dest)", thay vì "GetParameterValue (...)". Câu trả lời đã chỉnh sửa của anh ấy là chính xác. – CodingWithSpike

0

Ở cấp độ lý thuyết không phải là null thực sự giống như con trỏ trống trong C, có nghĩa là nó chứa địa chỉ bộ nhớ và đúng không? Nếu vậy thì nó cũng tương tự như trường hợp của một bộ phận bằng 0 trong Toán học mà kết quả là không xác định.

Người ta có thể làm như sau cho dòng này:

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

Chỉ cần loại bỏ chuỗi đầu tiên và bây giờ không có sự lặp lại:

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

Không nhất thiết những gì bạn đang tìm kiếm, mặc dù có câu hỏi về cách người ta giải thích null?

+0

Vấn đề không phải là "họ là loại null", đó là "loại vị trí lưu trữ này xảy ra hiện tại được đặt thành null" Vì vậy "DataTable dt = null", VM vẫn biết dt là Loại DataTable . – CodingWithSpike

+0

Trong việc thiết lập một biến thành null, nó không trỏ vào bất cứ điều gì, là quan điểm của tôi. Nếu bạn có 3 lớp, mỗi lớp được bắt nguồn từ một lớp khác, ví dụ: A có nguồn gốc từ B và B có nguồn gốc từ C, và bạn đã có một biến loại B được gán null, bạn không thể gán một biến kiểu A cho nó hay không? –

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

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

hoặc

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

theo cách đó chúng ta có thể sử dụng công tắc để quản lý các loại tài sản khác nhau.

7

Phương pháp mở rộng sau đây trả về kiểu của tham số của nó như nó đã được công bố, bất kể nội dung của nó:

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

Do đây là một phương pháp khuyến nông, đối số của nó có thể là một tham chiếu null, và tất cả các công trình sau đây OK:

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

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

Lưu ý rằng myObjTypemyNullObjType sẽ cả hai được thiết lập để System.Object, không System.String.

Nếu bạn thực sự muốn loại nội dung obj khi nó không phải là null, sau đó thay đổi dòng return tới:

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

Bạn sẽ nhận được một RuntimeBinderException nếu obj được khai báo là động. –

Các vấn đề liên quan