【问题标题】:Is there a way to pass a class property as a parameter to a method?有没有办法将类属性作为参数传递给方法?
【发布时间】:2019-07-30 14:23:42
【问题描述】:

我正在尝试找到一种方法来获取类的属性并将其与另一个变量一起传递给方法,以根据条件更新属性。例如

班级

public class MyClass{
    public string? Prop1 { get; set; }
    public string? Prop2 { get; set; }
    public bool? Prop3 { get; set; }
    public DateTime? Prop4 { get; set; }
    ... etc...
}

我想开始工作的测试代码...:

var obj = new MyClass();
MyCheckMethod(ref obj.Prop1, someCollection[0,1]);

在方法中:

private void MyCheckMethod(ref Object obj, string value)
{
     if (!string.isnullorempty(value))
     {    
          // data conversion may be needed here depending on data type of the property
          obj = value;
     }
}

我希望能够传递任何类的任何属性并仅在验证方法中传递的值后更新该属性。我希望我可以用泛型来做到这一点,但我还没有找到这样做的方法。或者,如果我把需要做的事情复杂化了。

问题在于对传入值的验证可能不仅仅是简单的 isnullorempy 检查。

我也想过做这样的事情:

private void MyCheckMethod(ref object obj, Action action)

然后我可以这样做:

...
MyCheckMethod(ref obj.Prop1, (somecollection[0,1]) => {
   ... etc....
})

所以我正在寻找一些关于如何进行的指导。

更新信息:

传入的数据都是字符串格式(这是第 3 方供应商提供数据的方式)。数据是通过 API 调用提供给第三方产品的……他们 SDK 的一部分。但是在我的课堂上,我需要有正确的数据类型。将字符串值转换为 datetime 用于日期,将字符串值转换为 int 用于 int 数据类型等...。另一个需要注意的是,如果数据类型没有有效值,则属性的默认值应为 NULL。

其他信息:

传入的数据始终为字符串格式。
例如:

我必须更新一个布尔属性。
传入值为“”。我测试看看字符串 Value 是否为 NullOrEmpty。所以我不会对财产做任何事情。

下一个属性数据类型是十进制。 传入值为“0.343”。 我测试以查看字符串值是否为 NullorEmpty。不是这样,一旦我进行转换等,我就可以更新属性......

希望这会有所帮助。

谢谢

【问题讨论】:

  • 能否将整个对象obj直接传递给方法MyCheckMethod
  • @YeldarKurmangaliyev - 问题是我只需要在值有效时更新属性,如果需要,然后转换为适当的数据类型。该属性需要保持为空,直到有一个有效值。另外,我有 100 多个属性,所以我试图消除任何臃肿的编码。
  • 价值从何而来?很有可能已经有一个工具可以完成您需要做的事情。
  • 什么决定了一个值是否有效,以及传入数据的类型是什么——它是对象、字符串还是其他什么?解决此问题的一种方法是更详细地描述预期用途。我认为许多答案(包括我的)都专注于从字面上回答您的问题,但我敢打赌有更好的方法。

标签: c#


【解决方案1】:

编辑后的完整解决方案:

 public static class Extensions
    {
        //create other overloads
        public static void MyCheckMethodDate<TObj>(this TObj obj,Expression<Func<TObj,DateTime>> property, string value)
        {
            obj.MyCheckMethod(property, value, DateTime.Parse);
        }

        public static void MyCheckMethod<TObj,TProp>(this TObj obj,Expression<Func<TObj,TProp>> property, string value,Func<string, TProp> converter)
        {
            if(string.IsNullOrEmpty(value))
                return;

            var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;

            if(null != propertyInfo && propertyInfo.CanWrite)
            {
              propertyInfo.SetValue(obj, converter(value));
            }
        }
    }

    public class Obj
    {
        public object Prop1{get;set;}
        public string Prop2{get;set;}
        public DateTime Prop3{get;set;}
    }

    public class Program
    {
        public static void Main()
        {
            var obj = new Obj();

            obj.MyCheckMethodDate(x=>x.Prop3, "2018-1-1");

            Console.WriteLine(obj.Prop3);
        }
    }

【讨论】:

  • 例如,此代码不允许您将 string 分配给 object 类型的属性。
  • 是的,它确实将字符串分配给对象类型的属性。刚刚测试过了。
  • 您的示例看起来缺少方法/用法调用的参数......
  • @MistyK 这仅适用于数据源与属性的数据类型相同的情况...请参阅我的更新信息。传入的数据将始终是字符串......属性数据类型可以是任何东西......
  • 写一个逻辑,如果是 DateTime 则转换 DateTime.Parse 等其他类型
【解决方案2】:

你可以传递一个 lambda 表达式:

void DoSomething<T>(Expression<Func<T>> property)
{
    var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
    if (propertyInfo == null)
    {
        throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
    }else{
        var name = ((MemberExpression)property.Body).Member.Name;
        var value = property.Compile();
        //Do whatever you need to do
    }
}

使用方法:

DoSomething(() => obj.Property1);

【讨论】:

    【解决方案3】:

    您不能传递对任意属性的引用。一个属性基本上实现为set_Propertyget_Property这两种方法,没有办法将它们捆绑在一起。

    一种选择是让您的检查器函数接受委托来访问该属性。例如:

    private void MyCheckMethod(Func<string> getter, Action<string> setter)
    {
         var value = getter();
         var newValue = value.ToUpper();
         setter(value);
    }
    

    所以现在你会这样说:

    public class MyClass
    {
        public string Prop1 { get; set; }
        public string Prop2 { get; set; }
    }
    
    var c = new MyClass();
    MyCheckMethod(() => c.Prop1, value => c.Prop1 = value);
    

    【讨论】:

    • 有,反射。
    • @MistyK - 这不是传递对属性的引用,而是传递一个 PropertyInfo 实例。这会很慢,容易出错并且不安全,这意味着曾经的编译时错误将变成运行时错误。
    • 慢一点?是的,但不是很明显,除非你每秒调用它数千次。容易出错?或许一点点。打字安全吗?看我的回答。
    【解决方案4】:

    对编译的表达式使用反射。 这比反射执行得更好,但比原生代码慢一点。

    它不是类型安全的,但您可以添加运行时验证。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      • 2019-12-09
      • 1970-01-01
      • 1970-01-01
      • 2022-09-27
      • 1970-01-01
      • 2017-07-10
      相关资源
      最近更新 更多