C# .Net通过键获取对象的属性值,深度不限

C# .Net通过键获取对象的属性值,深度不限,c#,dynamic,properties,C#,Dynamic,Properties,我希望能够访问任何深度的对象属性值,该深度只有属性的字符串键。此外,如果可能,请对列表属性使用集合索引。 因此,如果我有字符串“Person.namname”,那么我可以从和实例化的CaseConductor对象中获得值“Smith”。所以给一些像这样的设置代码 //- Load a caseConductor var caseConductor = new CaseConductor(); caseConductor.CaseID = "A00001"; // person caseCon

我希望能够访问任何深度的对象属性值,该深度只有属性的字符串键。此外,如果可能,请对列表属性使用集合索引。 因此,如果我有字符串“Person.namname”,那么我可以从和实例化的CaseConductor对象中获得值“Smith”。所以给一些像这样的设置代码

//- Load a caseConductor
var caseConductor = new CaseConductor();
caseConductor.CaseID = "A00001"; 
// person 
caseConductor.Person = new Person();
caseConductor.Person.Surname = "Smith" ;
caseConductor.Person.DOB = DateTime.Now ; 
// case note list
caseConductor.CaseNoteList = new List<Note>();
caseConductor.CaseNoteList.Add(new Note { NoteText = "A-1" , NoteDt  = DateTime.Now });
caseConductor.CaseNoteList.Add(new Note { NoteText = "B-2", NoteDt = DateTime.Now });
// I could do this ...
object val = caseConductor.SomeCleverFunction("Person.Surname");
// or this ...
object val = caseConductor.SomeCleverFunction("CaseNoteList[0].NoteText");
List<SdtElement> ccList = wordprocessingDocument.MainDocumentPart.Document.Descendants<SdtElement>().ToList();
foreach (var cc in ccList)
{
  string alias = cc.SdtProperties.GetFirstChild<SdtAlias>().Val.Value;
  switch (cc.GetType().Name)
  {
    case "SdtRun":
      SdtRun thisRun = (SdtRun)cc;
      //thisRun.Descendants<Text>().First().Text  = theValueToBePoked ; 
      break;
   }
}
//-加载外壳导体
var caseConductor=新caseConductor();
caseConductor.CaseID=“A00001”;
//人
casecondor.Person=新的Person();
casecondor.Person.name=“Smith”;
caseConductor.Person.DOB=DateTime.Now;
//病例记录表
caseConductor.CaseNoteList=新列表();
caseConductor.CaseNoteList.Add(新注释{NoteText=“A-1”,NoteDt=DateTime.Now});
caseConductor.CaseNoteList.Add(新注释{NoteText=“B-2”,NoteDt=DateTime.Now});
//我可以这样做。。。
object val=caseConductor.SomeCleverFunction(“Person.姓氏”);
//或者这个。。。
object val=caseConductor.SomeCleverFunction(“CaseNoteList[0].NoteText”);
以前有人这样做过吗? 下面是一些设置类

class Note
    {
        public Guid NoteID { get; set; }
        public string NoteText { get; set; }
        public DateTime? NoteDt { get; set; }
    }
    public class Person
    {
        public Guid PersonID { get; set; }
        public string Surname { get; set; }
        public string Forename { get; set; }
        public DateTime? DOB { get; set; }
    }
    class CaseConductor
    {
        public String CaseID{get;set;}
        public Person Person { get; set; }
        public List<Note> CaseNoteList { get; set; }
    }
课堂笔记
{
公共Guid NoteID{get;set;}
公共字符串NoteText{get;set;}
公共日期时间?NoteDt{get;set;}
}
公共阶层人士
{
公共Guid PersonID{get;set;}
公共字符串姓氏{get;set;}
公共字符串名{get;set;}
公共日期时间?DOB{get;set;}
}
班长
{
公共字符串CaseID{get;set;}
公众人物{get;set;}
公共列表CaseNoteList{get;set;}
}
我们的用例是使用OpenXMLSDK2在word数据消费模板中迭代一系列适当命名的内容控件,并在新创建的word文档中插入值,类似于以下内容

//- Load a caseConductor
var caseConductor = new CaseConductor();
caseConductor.CaseID = "A00001"; 
// person 
caseConductor.Person = new Person();
caseConductor.Person.Surname = "Smith" ;
caseConductor.Person.DOB = DateTime.Now ; 
// case note list
caseConductor.CaseNoteList = new List<Note>();
caseConductor.CaseNoteList.Add(new Note { NoteText = "A-1" , NoteDt  = DateTime.Now });
caseConductor.CaseNoteList.Add(new Note { NoteText = "B-2", NoteDt = DateTime.Now });
// I could do this ...
object val = caseConductor.SomeCleverFunction("Person.Surname");
// or this ...
object val = caseConductor.SomeCleverFunction("CaseNoteList[0].NoteText");
List<SdtElement> ccList = wordprocessingDocument.MainDocumentPart.Document.Descendants<SdtElement>().ToList();
foreach (var cc in ccList)
{
  string alias = cc.SdtProperties.GetFirstChild<SdtAlias>().Val.Value;
  switch (cc.GetType().Name)
  {
    case "SdtRun":
      SdtRun thisRun = (SdtRun)cc;
      //thisRun.Descendants<Text>().First().Text  = theValueToBePoked ; 
      break;
   }
}
List ccList=wordprocessingDocument.MainDocumentPart.Document.subjects().ToList();
foreach(ccList中的var cc)
{
字符串别名=cc.SdtProperties.GetFirstChild().Val.Value;
开关(cc.GetType().Name)
{
案例“SdtRun”:
SdtRun thisRun=(SdtRun)cc;
//thisRun.subjects().First().Text=要记录的值;
打破
}
}

使用良好的旧反射。我已经测试过了,这确实有效:

    public static object GetValue(object o, string propertyName)
    {
        Type type = o.GetType();
        PropertyInfo propertyInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance ).Where(x => x.Name == propertyName).FirstOrDefault();
        if(propertyInfo!=null)
        {
            return propertyInfo.GetValue(o, BindingFlags.Instance, null, null, null);
        }
        else
        {
            return null; // or throw exception 
        }
    }
我想 caseConductor.SomeCleverFunction 不是静态方法,并且可以访问Person对象,并且Person对象本身是公共属性

我还假设您希望传递一个字符串,如“prop.address.street”,其中每个子属性都是一个类,其中包含一个具有该名称的puplic属性

  • 拆分句点上的字符串输入,找到最左边的字符串
  • 使用反射获取属性列表(typeof(caseconductor).GetProperties()
  • 找到匹配的属性,对其调用GetValue,传递最后一个已知的实体对象(以“this”开头)并存储对它的引用
  • 如果字符串左侧有更多子属性,请重复步骤1,删除字符串最左侧的部分
  • 否则,使用步骤3中的最后一个GetValue()返回对象对属性调用GetValue(),并返回它
  • 比如:

    “prop.address.street”->从“this”和GetValue中查找属性“prop”

    还有更多的“.”重复,存储返回值

    “address.street”->从上次返回的GetValue中查找属性“address”,并获取其值

    还有更多的“.”重复,存储返回值

    “street”->从上次返回的GetValue中查找属性“street”,并返回其值

    字符串结尾,返回最后一个值

    编辑-

    这是相当粗糙的,但把它扔进LinqPAD看看

    编辑#2-您应该能够使用下面的^语法索引到数组中

    这又是一个非常粗糙的例子,只够得到一个有效的例子

    编辑#3-稍微清理了示例,并将其从我的示例类更改为您的示例类

    void Main()
    {
     //- Load a caseConductor 
     var caseConductor = new CaseConductor(); 
     caseConductor.CaseID = "A00001";  
     // person  
     caseConductor.Person = new Person(); 
     caseConductor.Person.Surname = "Smith" ; 
     caseConductor.Person.DOB = DateTime.Now ;  
     // case note list 
     caseConductor.CaseNoteList = new List<Note>(); 
     caseConductor.CaseNoteList.Add(new Note { NoteText = "A-1" , NoteDt  = DateTime.Now }); 
     caseConductor.CaseNoteList.Add(new Note { NoteText = "B-2", NoteDt = DateTime.Now }); 
     // I could do this ... 
     string val1 = caseConductor.GetPropertyValue<string>("Person.Surname"); 
     // or this ... 
     Note val2 =  caseConductor.GetPropertyValue<Note>("CaseNoteList^1"); 
     val1.Dump("val1"); //this is a string
     val2.Dump("val2"); //this is a Note
    }
    
    public static class extensions
    {
     public static T GetPropertyValue<T>(this object o,string Properties) where T:class
     {
    
      var properties = Properties.Split('.');
      var indexsplit = properties[0].Split('^');
    
      var current = indexsplit[0];
    
    
      var prop = (from p  in o.GetType().GetProperties() where p.Name == current select p).Take(1).Single();
      var val = prop.GetValue(o,null);
    
      if(indexsplit.Length>1)
      {
       var index = int.Parse(indexsplit[1]);
       IList ival = (IList)val;
       val = ival[index];
      }
    
      if(properties[0] == Properties)
       return (T)val;
      else
       return val.GetPropertyValue<T>(Properties.Replace(properties[0]+".",""));
     }
    }
    
    
    class Note 
     { 
      public Guid NoteID { get; set; } 
      public string NoteText { get; set; } 
      public DateTime? NoteDt { get; set; } 
     } 
     public class Person 
     { 
      public Guid PersonID { get; set; } 
      public string Surname { get; set; } 
      public string Forename { get; set; } 
      public DateTime? DOB { get; set; } 
     } 
     class CaseConductor 
     { 
      public String CaseID{get;set;} 
      public Person Person { get; set; } 
      public List<Note> CaseNoteList { get; set; } 
     } 
    
    void Main()
    {
    //-装箱子
    var caseConductor=新caseConductor();
    caseConductor.CaseID=“A00001”;
    //人
    casecondor.Person=新的Person();
    casecondor.Person.name=“Smith”;
    caseConductor.Person.DOB=DateTime.Now;
    //病例记录表
    caseConductor.CaseNoteList=新列表();
    caseConductor.CaseNoteList.Add(新注释{NoteText=“A-1”,NoteDt=DateTime.Now});
    caseConductor.CaseNoteList.Add(新注释{NoteText=“B-2”,NoteDt=DateTime.Now});
    //我可以这样做。。。
    string val1=caseConductor.GetPropertyValue(“Person.姓氏”);
    //或者这个。。。
    Note val2=caseConductor.GetPropertyValue(“CaseNoteList^1”);
    val1.Dump(“val1”);//这是一个字符串
    val2.Dump(“val2”);//这是一张便条
    }
    公共静态类扩展
    {
    公共静态T GetPropertyValue(此对象为o,字符串属性),其中T:class
    {
    var properties=properties.Split('.');
    var indexsplit=properties[0]。拆分(“^”);
    无功电流=指数分裂[0];
    var prop=(从o.GetType().GetProperties()中的p开始,其中p.Name==当前选择p);
    var val=prop.GetValue(o,null);
    如果(索引分裂长度>1)
    {
    var index=int.Parse(indexsplit[1]);
    IList ival=(IList)val;
    val=ival[指数];
    }
    if(属性[0]==属性)
    返回(T)val;
    其他的
    返回val.GetPropertyValue(Properties.Replace(Properties[0]+“,”);
    }
    }
    课堂笔记
    { 
    公共Guid NoteID{get;set;}
    公共字符串NoteText{get;set;}
    公共日期时间?NoteDt{get;set;}
    } 
    公共阶层人士
    { 
    公共Guid PersonID{get;set;}
    公共字符串姓氏{get;set;}
    公共字符串名{get;set;}
    公共日期时间?DOB{get;set;}
    } 
    班长
    { 
    公共字符串CaseID{get;set;}
    公众人物{get;set;}
    公共列表CaseNoteList{get;set;}
    } 
    
    好的,我想出了一个继续Aliosted和