Bagaimana cara memeriksa apakah properti ada pada tipe anonim dinamis di c #?

122

Saya memiliki tipe objek anonim yang saya terima sebagai dinamika dari metode yang saya ingin periksa di properti yang ada pada objek itu.

....
var settings = new {
                   Filename="temp.txt",
                   Size=10
}
...

function void Settings(dynamic settings) {
var exists = IsSettingExist(settings,"Filename")
}

Bagaimana cara menerapkan IsSettingExist?

David MZ
sumber
Jika Anda menemukan diri Anda sangat bergantung pada objek dinamis, mungkin ada baiknya melihat F # - Ngomong-ngomong, Avatar Bagus
Piotr Kula

Jawaban:

150
  public static bool IsPropertyExist(dynamic settings, string name)
  {
    if (settings is ExpandoObject)
      return ((IDictionary<string, object>)settings).ContainsKey(name);

    return settings.GetType().GetProperty(name) != null;
  }

  var settings = new {Filename = @"c:\temp\q.txt"};
  Console.WriteLine(IsPropertyExist(settings, "Filename"));
  Console.WriteLine(IsPropertyExist(settings, "Size"));

Keluaran:

 True
 False
Serj-Tm
sumber
3
Ini tidak bekerja pada objek dinamis. Itu selalu mengembalikan nol.
evilom
@evilom @Shikasta_Kashti Apakah Anda mencoba menggunakan metode ini dengan MVC ViewBag? Jika demikian, lihat stackoverflow.com/a/24192518/70345
Ian Kemp
@Bayu_joo. Ini adalah konvensi pengkodean yang tidak biasa. Beberapa orang menyukai awalan "Is" pada semua properti boolean. Konsistensi seperti itu dapat mencegah Anda dari keharusan menebak beberapa karakter pertama dari suatu pengenal (setelah itu, Intellisense berfungsi), tetapi dengan mengorbankan membuat bahasa Inggris menjadi sedikit canggung dalam kasus seperti ini.
solublefish
Saya menemukan bentuk kata kerja yang tidak valid dari Isawalan menjadi lebih membingungkan daripada yang akan digunakan HasProperty. Saya juga akan mengatakan bahwa menggunakan awalan yang salah secara tata bahasa seperti ini sebenarnya non-idiomatik di C♯.
Ben Collins
ExpandoObject tidak sama dengan tipe anonim. Apakah saya salah tentang itu?
ryanwebjackson
38
public static bool HasProperty(dynamic obj, string name)
{
    Type objType = obj.GetType();

    if (objType == typeof(ExpandoObject))
    {
        return ((IDictionary<string, object>)obj).ContainsKey(name);
    }

    return objType.GetProperty(name) != null;
}
Sergey
sumber
objType.GetProperty(name) != null;mengembalikan null pada properti yang ada
Matas Vaitkevicius
3
objType.GetProperty(name) != nullakan selalu mengembalikan a bool, yang (menurut definisi) tidak akan pernah bisa null.
Alex McMillan
@AlexMcMillan Tidak yakin di dimensi apa Anda tinggal di mana Type.GetProperty(string)untuk properti yang tidak ada mengembalikan apa pun selain null.
Ian Kemp
2
@IanKemp, AlexMcMillan mengatakan objType.GetProperty (name)! = Null dalam membalas komentar MatasVaitkevicius sebenarnya.
Sergey
15

jika Anda dapat mengontrol pembuatan / penerusan objek pengaturan, saya akan merekomendasikan menggunakan ExpandoObject sebagai gantinya.

dynamic settings = new ExpandoObject();
settings.Filename = "asdf.txt";
settings.Size = 10;
...

function void Settings(dynamic settings)
{
    if ( ((IDictionary<string, object>)settings).ContainsKey("Filename") )
        .... do something ....
}
Mike Corcoran
sumber
Saya tidak dapat mengubahnya, dapatkah saya mentransmisikan ke ExpendoObject?
David MZ
6

Ini berfungsi untuk jenis anonim ExpandoObject, Nancy.DynamicDictionaryatau apa pun yang dapat ditransmisikan IDictionary<string, object>.

    public static bool PropertyExists(dynamic obj, string name) {
        if (obj == null) return false;
        if (obj is IDictionary<string, object> dict) {
            return dict.ContainsKey(name);
        }
        return obj.GetType().GetProperty(name) != null;
    }
Seth Reno
sumber
2
Solusi bagus. Saya perlu menambahkan satu lagi pernyataan IF saat mengubah string JSON menjadi JObject .... "if (obj adalah Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name); "
rr789
1
Juga bekerja untuk saya. Jawaban luar biasa Seth Reno. Saya juga menambahkan "if (obj adalah Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);" dalam fungsi di atas seperti yang disarankan oleh rr789. Jadi, harap edit juga jawaban Anda untuk menyertakannya.
Brijesh Kumar Tripathi
1
Terima kasih @BrijeshKumarTripathi! Ini persis skenario saya.
ryanwebjackson
4

Ini bekerja untuk saya-:

  public static bool IsPropertyExist(dynamic dynamicObj, string property)
       {
           try
           {
               var value=dynamicObj[property].Value;
               return true;
           }
           catch (RuntimeBinderException)
           {

               return false;
           }

       }
pengguna3359453
sumber
14
Membiarkan pengecualian terjadi dan kemudian menangkapnya bukanlah solusi yang disukai karena ada banyak overhead yang terkait dengan melempar dan menangkap. Ini hanya pilihan terakhir. Pengecualian dirancang untuk situasi yang seharusnya tidak terjadi selama eksekusi seperti jaringan yang tidak tersedia. Ada solusi yang jauh lebih baik di sini.
Apapun Man
Gagal dengan RuntimeBinderExceptiondan dynamicObj[property].Value ketika nilai sebenarnya ada ... var value = dynamicObj[property]cukup ... dan ketika itu tidak ada KeyNotFoundException di Dictionarydilemparkan ... lihat di bawah ...
Matas Vaitkevicius
Ini bukan solusi yang dapat diterima untuk menggunakan pengecualian dalam logika bisnis. 1 kelas, semester 2.
Artem G
3

Tak satu pun dari solusi di atas yang berfungsi untuk dynamicitu berasal dari Json, namun saya berhasil mengubahnya dengan Try catch(oleh @ user3359453) dengan mengubah jenis pengecualian yang dilemparkan ( KeyNotFoundExceptionbukan RuntimeBinderException) menjadi sesuatu yang benar-benar berfungsi ...

public static bool HasProperty(dynamic obj, string name)
    {
        try
        {
            var value = obj[name];
            return true;
        }
        catch (KeyNotFoundException)
        {
            return false;
        }
    }

masukkan deskripsi gambar di sini

Semoga ini menghemat waktu Anda.

Matas Vaitkevicius
sumber
1
Menggunakan pengecualian untuk hal-hal seperti ini tidak disarankan. Seharusnya memilih sesuatu seperti casting ke JObject dan menggunakan .Property ()! = Null
Gaspa79
3

Menggabungkan dan memperbaiki jawaban dari Serj-TM dan user3359453 sehingga berfungsi dengan ExpandoObject dan DynamicJsonObject. Ini berhasil untuk saya.

public static bool HasPropertyExist(dynamic settings, string name)
{
    if (settings is System.Dynamic.ExpandoObject)
        return ((IDictionary<string, object>)settings).ContainsKey(name);

    if (settings is System.Web.Helpers.DynamicJsonObject)
    try
    {
        return settings[name] != null;
    }
    catch (KeyNotFoundException)
    {
        return false;
    }


    return settings.GetType().GetProperty(name) != null;
}
Bruno Marotta
sumber
2

Menggunakan refleksi, inilah fungsi yang saya gunakan:

public static bool doesPropertyExist(dynamic obj, string property)
{
    return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
}

kemudian..

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}
Chtiwi Malek
sumber
2
GetProperties () tidak mencantumkan Anggota dinamis di DynamicObject. Ada fungsi GetDynamicMemberNames () khusus untuk itu.
Marco Guignard
Menggunakan ekspresi lambda Whereterlebih dahulu, kemudian Anyberlebihan, karena Anda juga dapat merumuskan ekspresi pemfilteran Any.
pholpar
1

Jika seseorang perlu menangani objek dinamis yang berasal dari Json, saya telah memodifikasi jawaban Seth Reno untuk menangani objek dinamis yang dideserialisasi dari NewtonSoft.Json.JObjcet.

public static bool PropertyExists(dynamic obj, string name)
    {
        if (obj == null) return false;
        if (obj is ExpandoObject)
            return ((IDictionary<string, object>)obj).ContainsKey(name);
        if (obj is IDictionary<string, object> dict1)
            return dict1.ContainsKey(name);
        if (obj is IDictionary<string, JToken> dict2)
            return dict2.ContainsKey(name);
        return obj.GetType().GetProperty(name) != null;
    }
Kuroro
sumber
0

Untuk memperluas jawaban dari @Kuroro, jika Anda perlu menguji apakah propertinya kosong, di bawah ini akan berfungsi.

public static bool PropertyExistsAndIsNotNull(dynamic obj, string name)
{
    if (obj == null) return false;
    if (obj is ExpandoObject)
    {
        if (((IDictionary<string, object>)obj).ContainsKey(name))
            return ((IDictionary<string, object>)obj)[name] != null;
        return false;
    }
    if (obj is IDictionary<string, object> dict1)
    {
        if (dict1.ContainsKey(name))
            return dict1[name] != null;
        return false;
    }
    if (obj is IDictionary<string, JToken> dict2)
    {
        if (dict2.ContainsKey(name))
            return (dict2[name].Type != JTokenType.Null && dict2[name].Type != JTokenType.Undefined);
        return false;
    }
    if (obj.GetType().GetProperty(name) != null)
        return obj.GetType().GetProperty(name).GetValue(obj) != null;
    return false;
}
Mötz
sumber