代码之家  ›  专栏  ›  技术社区  ›  ctrlShiftBryan

通过引用传递属性

  •  22
  • ctrlShiftBryan  · 技术社区  · 16 年前

    是否仍要通过引用传递对象的属性?我知道我可以传递整个对象,但我想指定要设置的对象的属性并检查它的类型,这样我就知道如何解析了。我应该采取另一种方法吗(我无论如何都不能更改原始对象)?

    public class Foo{
        public Foo(){}
        public int Age { get; set; }
    }
    
    private void setFromQueryString(object aProperty, String queryString, HttpContext context)
    {
        //here I want to handle pulling the values out of 
        //the query string and parsing them or setting them
        //to null or empty string...
        String valueString = context.Request.QueryString[queryString].ToString(); 
    
        //I need to check the type of the property that I am setting.
    
        //this is null so I can't check it's type
        Type t = aProperty.GetType();
    }
    
    private void callingMethod(HttpContext context)
    {
        Foo myFoo = new Foo();
        setFromQueryString(myFoo.Age, "inputAge", context);
    }
    
    8 回复  |  直到 16 年前
        1
  •  18
  •   SLaks    16 年前

    可以使用lambda表达式调用函数:

    private void setFromQueryString<T>(Action<T> setter, String queryString, HttpContext context) 
    { 
        //here I want to handle pulling the values out of  
        //the query string and parsing them or setting them 
        //to null or empty string... 
        String valueString = context.Request.QueryString[queryString].ToString();  
    
        //I need to check the type of the property that I am setting. 
    
        //this is null so I can't check it's type 
        Type t = typeof(T); 
        ...
        setter(value);
    } 
    

    你可以这样称呼它:

    setFromQueryString<int>(i => myFoo.Age = i, "inputAge", context);
    

    编辑 :如果您 真正地 想要类型推断:

    private void setFromQueryString<T>(Func<T> getter, Action<T> setter, String queryString, HttpContext context) {
        ...
    }
    setFromQueryString(() => myFoo.Age, i => myFoo.Age = i, "inputAge", context);
    
        2
  •  5
  •   casperOne    16 年前

    不,无法通过引用直接传递属性。VisualBasic在语言中提供了这种支持,方法是将属性的值放入一个临时变量中,然后通过引用传递,并在返回时重新分配。

    在C中,只能通过传递 Func<T> 获取属性值,以及 Action<T> 用于设置值(使用闭包),其中 T 是属性的类型。

        3
  •  5
  •   Zach Johnson    16 年前

    可以使用相应的方法和委托包装该属性并传递委托。

    delegate int IntGetter<T>(T obj);
    delegate void IntSetter<T>(T obj, int value);
    
    int GetAge(Foo foo)
    {
        return foo.Age;
    }
    
    void SetAge(Foo foo, int value)
    {
        foo.Age = value;
    }
    
    private void callingMethod(HttpContext context)
    {
        Foo myFoo = new Foo();
        // need to also pass foo so the property can be set
        setFromQueryString(new IntSetter<Foo>(SetAge), foo, "inputAge", context);
    }
    
    private void setFromQueryString<T>(
        IntSetter<T> intSetter, 
        T obj, 
        String queryString, 
        HttpContext context)
    {
        String valueString = context.Request.QueryString[queryString].ToString(); 
        intSetter(T, valueString);
    }
    
        4
  •  5
  •   Jeff Yates    16 年前

    正如其他人所指出的,您可以使用委托来实现这一点,使用许多指定委托的方法之一。但是,如果您打算定期这样做,那么应该考虑创建一个包装类型,以便通过引用传递包装所需委托的属性,它可能会创建更好的API。

    例如:

    class PropertyReference<T>
    {
       public T Value
       {
           get
           {
               return this.getter();
           }
    
           set
           {
               this.setter(value);
           }
       }
    
       public PropertyReference(Func<T> getter, Action<T> setter)
       {
          this.getter = getter;
          this.setter = setter;
       }
    }
    

    这样,您就可以传递对属性的引用,并通过设置引用值来修改它。

    var reference = new PropertyReference(
                            () => this.MyValue,
                            x => this.MyValue = x);
    
    reference.Value = someNewValue;
    
        5
  •  2
  •   Fadrian Sudaman    16 年前

    使用lambda传递函数可能是最优雅的,但是如果您只想简单地解决您的问题

    private void callingMethod(HttpContext context)
    {
        Foo myFoo = new Foo();
        int myAge = myFoo.Age;
        setFromQueryString(ref myAge, "inputAge", context);
        myFoo.Age = myAge;    
    }
    
    private void setFromQueryString(ref int age, String queryString, HttpContext context)
    {
    ...
    }
    
        6
  •  2
  •   pdr    16 年前

    为什么不使用泛型并返回对象?

    private T setFromQueryString<T>(String queryString, HttpContext context)
    {
        String valueString = context.Request.QueryString[queryString].ToString(); 
    
        // Shouldn't be null any more
        Type t = typeof(T);
    }
    
    private void callingMethod(HttpContext context)
    {
        Foo myFoo = new Foo();
        myFoo.Age = setFromQueryString<int>("inputAge", context);
    }
    

    不太清楚为什么你会这样做,但鉴于你是,你可以这样做。

    private void setFromQueryString(ref T aProperty, String queryString, HttpContext context)
    {
        String valueString = context.Request.QueryString[queryString].ToString(); 
    
        // Shouldn't be null any more
        Type t = typeof(T);
    }
    
    private void callingMethod(HttpContext context)
    {
        Foo myFoo = new Foo();
        setFromQueryString(ref myFoo.Age, "inputAge", context);
    }
    
        7
  •  1
  •   Robert C. Barth    16 年前

    你为什么这么复杂?您在编译时就知道属性的类型,只需使用一行代码就可以了:

    Foo.Age = int.Parse(context.Request.QueryString["Parameter"]);
    

    如果需要检查类型,只需添加一个包装int.typarse()的小函数,如果在querystring值中得到“pdq”,而不是数字,则返回无害的结果(例如0)。

        8
  •  1
  •   Robert C. Barth    16 年前

    以下是一个完全不同的解决方案:

    创建从System.Web.UI.Page派生的类,这些类的属性为queryString参数。另外,使用实用程序函数(参见下面的converttype),您不需要做太多的工作来从querystring中获取数据。最后,在这些派生类中,定义一个静态内部类,该类包含作为querystring参数名称的常量,这样您就不需要在任何地方引用任何魔力值。

    我通常为我的项目定义一个基本页类,这使得它成为一个方便的地方来执行所有页面上发生的常见事情,以及一些实用程序函数:

    public class MyBasePage : System.Web.UI.Page
    {
    
      public T GetQueryStringValue<T>(
            string value,
            T defaultValue,
            bool throwOnBadConvert)
      {
        T returnValue;
    
        if (string.IsNullOrEmpty(value))
          return defaultValue;
        else
          returnValue = ConvertType<T>(value, defaultValue);
    
        if (returnValue == defaultValue && throwOnBadConvert)
          // In production code, you'd want to create a custom Exception for this
          throw new Exception(string.Format("The value specified '{0}' could not be converted to type '{1}.'", value, typeof(T).Name));
        else
          return returnValue;
      }
    
      // I usually have this function as a static member of a global utility class because
      // it's just too useful to only have here.
      public T ConvertType<T>(
            object value,
            T defaultValue)
      {
        Type realType = typeof(T);
    
        if (value == null)
          return defaultValue;
    
        if (typeof(T) == value.GetType())
          return (T)value;
    
        if (typeof(T).IsGenericType)
          realType = typeof(T).GetGenericArguments()[0];
    
        if (realType == typeof(Guid))
          return (T)Convert.ChangeType(new Guid((string)value), realType);
        else if (realType == typeof(bool))
        {
          int i;
          if (int.TryParse(value.ToString(), out i))
            return (T)Convert.ChangeType(i == 0 ? true : false, typeof(T));
        }
    
        if (value is Guid && typeof(T) == typeof(string))
          return (T)Convert.ChangeType(((Guid)value).ToString(), typeof(T));
    
        if (realType.BaseType == typeof(Enum))
          return (T)Enum.Parse(realType, value.ToString(), true);
    
        try
        {
          return (T)Convert.ChangeType(value, realType);
        }
        catch
        {
          return defaultValue;
        }
      }
    }
    
    public class MyPage : MyBasePage
    {
      public static class QueryStringParameters
      {
        public const string Age= "age";
      }
    
      public int Age
      {
        get 
        { 
         return base.GetQueryStringValue<int>(Request[QueryStringParameters.Age], -1);
        }
      }
    }
    

    然后,在常规页面的代码隐藏部分,现在看起来是这样的:

    public partial class MyWebPage : MyPage
    {
      protected void Page_Load(object sender, EventArgs e)
      {
        Foo myFoo = new Foo();
        Foo.Age = this.Age;
      }
    }
    

    它使代码隐藏在类后面 非常 清理(如您所见),并且很容易维护,因为所有繁重的提升都是由两个在每个页面类中重用的函数(getquerystringvalue和changetype)完成的,并且所有内容都是类型安全的(您将在getquerystringvalue中注意到,您可以指定函数是否hr如果值无法转换或仅使用返回默认值,则显示rows;这两个值都适用于不同的时间,具体取决于您的应用程序)。

    此外,您甚至可以很容易地编写一个vs插件或codesmith脚本来生成派生的page类。我发现新开发人员很难理解他们传递的代表和内容。

    推荐文章