Câu trả lời:
Theo MSDN , tuyên bố cho thấy nó đang thực hiện IDadata:
public sealed class ExpandoObject : IDynamicMetaObjectProvider,
IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>,
IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged
Bạn có thể sử dụng điều này để xem nếu một thành viên được xác định:
var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
// expandoObject.SomeMember exists.
}
Một sự phân biệt quan trọng cần phải được thực hiện ở đây.
Hầu hết các câu trả lời ở đây là cụ thể cho ExpandoObject được đề cập trong câu hỏi. Nhưng một cách sử dụng phổ biến (và lý do để đáp ứng câu hỏi này khi tìm kiếm) là khi sử dụng ASP.Net MVC ViewBag. Đó là một triển khai / lớp con tùy chỉnh của DynamicObject, sẽ không ném Ngoại lệ khi bạn kiểm tra bất kỳ tên thuộc tính tùy ý nào cho null. Giả sử bạn có thể khai báo một tài sản như:
@{
ViewBag.EnableThinger = true;
}
Sau đó, giả sử bạn muốn kiểm tra giá trị của nó và liệu nó có được đặt hay không - liệu nó có tồn tại hay không. Sau đây là hợp lệ, sẽ biên dịch, sẽ không đưa ra bất kỳ ngoại lệ nào và cung cấp cho bạn câu trả lời đúng:
if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
// Do some stuff when EnableThinger is true
}
Bây giờ hãy thoát khỏi tuyên bố của EnableThinger. Cùng mã biên dịch và chạy đúng. Không cần suy tư.
Không giống như ViewBag, ExpandoObject sẽ ném nếu bạn kiểm tra null trên một thuộc tính không tồn tại. Để có được chức năng nhẹ nhàng hơn của MVC ViewBag khỏi các dynamic
đối tượng của bạn , bạn sẽ cần sử dụng một triển khai động mà không ném.
Bạn chỉ có thể sử dụng triển khai chính xác trong MVC ViewBag:
. . .
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = ViewData[binder.Name];
// since ViewDataDictionary always returns a result even if the key does not exist, always return true
return true;
}
. . .
Bạn có thể thấy nó được gắn vào MVC Views ở đây, trong MVC ViewPage:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs
Chìa khóa cho hành vi duyên dáng của DynamicViewDataDipedia là việc triển khai Từ điển trên ViewDataDipedia, tại đây:
public object this[string key]
{
get
{
object value;
_innerDictionary.TryGetValue(key, out value);
return value;
}
set { _innerDictionary[key] = value; }
}
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDipedia.cs
Nói cách khác, nó luôn trả về một giá trị cho tất cả các khóa, bất kể cái gì trong đó - nó chỉ trả về null khi không có gì ở đó. Tuy nhiên, ViewDataDipedia có trách nhiệm gắn liền với Mô hình của MVC, vì vậy tốt hơn hết là chỉ loại bỏ các phần từ điển duyên dáng để sử dụng bên ngoài Chế độ xem MVC.
Quá lâu để thực sự đăng tất cả can đảm ở đây - hầu hết chỉ thực hiện IDadata - nhưng đây là một đối tượng động (lớp DDict
) không đưa ra kiểm tra null cho các thuộc tính chưa được khai báo, trên Github:
https://github.com/b9chris/GracefulDocateDixi
Nếu bạn chỉ muốn thêm nó vào dự án của mình thông qua NuGet, tên của nó là GracefulDocateDipedia .
Tôi đã trả lời một câu hỏi rất giống nhau gần đây: Làm thế nào để tôi phản ánh về các thành viên của đối tượng động?
Một thời gian ngắn, ExpandoObject không phải là đối tượng động duy nhất bạn có thể nhận được. Sự phản chiếu sẽ hoạt động đối với các loại tĩnh (các loại không triển khai ID ẩnMetaObjectProvider). Đối với các loại thực hiện giao diện này, sự phản chiếu về cơ bản là vô dụng. Đối với ExpandoObject, bạn chỉ cần kiểm tra xem thuộc tính có được xác định là khóa trong từ điển cơ bản hay không. Đối với các triển khai khác, nó có thể là thách thức và đôi khi cách duy nhất là làm việc với các ngoại lệ. Để biết chi tiết, hãy theo liên kết ở trên.
CẬP NHẬT: Bạn có thể sử dụng các đại biểu và cố gắng lấy một giá trị từ thuộc tính đối tượng động nếu nó tồn tại. Nếu không có tài sản, chỉ cần bắt ngoại lệ và trả về false.
Hãy xem, nó hoạt động tốt cho tôi:
class Program
{
static void Main(string[] args)
{
dynamic userDynamic = new JsonUser();
Console.WriteLine(IsPropertyExist(() => userDynamic.first_name));
Console.WriteLine(IsPropertyExist(() => userDynamic.address));
Console.WriteLine(IsPropertyExist(() => userDynamic.last_name));
}
class JsonUser
{
public string first_name { get; set; }
public string address
{
get
{
throw new InvalidOperationException("Cannot read property value");
}
}
}
static bool IsPropertyExist(GetValueDelegate getValueMethod)
{
try
{
//we're not interesting in the return value. What we need to know is whether an exception occurred or not
getValueMethod();
return true;
}
catch (RuntimeBinderException)
{
// RuntimeBinderException occurred during accessing the property
// and it means there is no such property
return false;
}
catch
{
//property exists, but an exception occurred during getting of a value
return true;
}
}
delegate string GetValueDelegate();
}
Đầu ra của mã là như sau:
True
True
False
IsPropertyExist
. Trong ví dụ này, bạn biết người ta có thể ném một InvalidOperationException
. Trong thực tế, bạn không biết ngoại lệ nào có thể bị ném. +1 để chống lại sự sùng bái hàng hóa.
Tôi muốn tạo một phương thức mở rộng để tôi có thể làm một cái gì đó như:
dynamic myDynamicObject;
myDynamicObject.propertyName = "value";
if (myDynamicObject.HasProperty("propertyName"))
{
//...
}
... nhưng bạn không thể tạo tiện ích mở rộng ExpandoObject
theo tài liệu C # 5 (thông tin thêm ở đây ).
Vì vậy, tôi đã kết thúc việc tạo ra một người trợ giúp lớp:
public static class ExpandoObjectHelper
{
public static bool HasProperty(ExpandoObject obj, string propertyName)
{
return ((IDictionary<String, object>)obj).ContainsKey(propertyName);
}
}
Để dùng nó:
// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
...
}
Tại sao bạn không muốn sử dụng Reflection để có được tập hợp các loại phù hợp? Như thế này
dynamic v = new Foo();
Type t = v.GetType();
System.Reflection.PropertyInfo[] pInfo = t.GetProperties();
if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }). GetValue(v, null) != null))
{
//PropName initialized
}
Phương thức mở rộng này kiểm tra sự tồn tại của một thuộc tính và sau đó trả về giá trị hoặc null. Điều này hữu ích nếu bạn không muốn các ứng dụng của mình đưa ra các ngoại lệ không cần thiết, ít nhất là các ứng dụng bạn có thể giúp đỡ.
public static object Value(this ExpandoObject expando, string name)
{
var expandoDic = (IDictionary<string, object>)expando;
return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
}
Nếu có thể được sử dụng như vậy:
// lookup is type 'ExpandoObject'
object value = lookup.Value("MyProperty");
hoặc nếu biến cục bộ của bạn là 'động', trước tiên bạn sẽ phải chuyển nó sang ExpandoObject.
// lookup is type 'dynamic'
object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");
Tùy thuộc vào trường hợp sử dụng của bạn, nếu null có thể được coi là giống như không xác định, bạn có thể biến ExpandoObject của mình thành DynamicJsonObject.
dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
x.a = 1;
x.b = 2.50;
Console.WriteLine("a is " + (x.a ?? "undefined"));
Console.WriteLine("b is " + (x.b ?? "undefined"));
Console.WriteLine("c is " + (x.c ?? "undefined"));
Đầu ra:
a is 1
b is 2.5
c is undefined
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
Này các bạn hãy ngừng sử dụng Reflection cho mọi thứ, nó tiêu tốn rất nhiều chu kỳ CPU.
Đây là giải pháp:
public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public int Count
{
get
{
return dictionary.Count;
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
if (!dictionary.TryGetValue(binder.Name, out result))
result = "undefined";
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
}
Hãy thử cái này
public bool PropertyExist(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName) != null;
}
dynamic
các đối tượng (luôn trả về null
).
data.myProperty
; nó kiểm tra những gìtypeof data.myProperty
trả về. Đó là chính xácdata.myProperty
có thể tồn tại và được đặt thànhundefined
, nhưng trong trường hợp đó,typeof
sẽ trả lại một cái gì đó khác hơn"undefined"
. Vì vậy, mã này không hoạt động.