无论如何通过引用传递Object的属性?我知道我可以传递整个对象,但是我想指定要设置的对象的属性并检查它的类型,以便我知道如何解析。我是否可以采取另一种方法(无论如何我都无法改变原始物体)?
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);
}
答案 0 :(得分:18)
您可以使用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);
答案 1 :(得分:5)
您可以使用相应的方法和委托包装该属性并传递委托。
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);
}
答案 2 :(得分:5)
不,没有办法通过引用直接传递属性。 Visual Basic通过将属性的值放入临时变量,然后通过引用传递并在返回时重新分配,在语言中提供此支持。
在C#中,您只能通过传递Func<T>
来获取属性值来近似此行为,并使用Action<T>
来设置值(使用闭包),其中T
是该物业的类型。
答案 3 :(得分:5)
正如其他人所指出的那样,您可以使用委托来执行此操作,使用多种方法之一来指定委托。但是,如果您打算定期执行此操作,则应考虑创建一个包装类型,以便通过引用传递属性来包装所需的委托,它可以创建更好的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;
答案 4 :(得分:2)
为什么不使用泛型并返回对象?
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);
}
答案 5 :(得分:2)
使用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 :(得分:1)
你为什么这么复杂?你知道编译时属性的类型,只需用一行代码就可以轻松实现:
Foo.Age = int.Parse(context.Request.QueryString["Parameter"]);
如果你需要检查类型,只需添加一个包含int.TryParse()的小函数,如果在查询字符串值而不是数字中得到“pdq”,则返回一个无害的结果(例如0)。
答案 7 :(得分:1)
这是一个完全不同的解决方案:
创建从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你可以指定函数是否抛出,如果值无法转换或只使用返回默认值;两者都适用于不同的时间,取决于你的应用程序)。
此外,您甚至可以轻松编写VS插件或CodeSmith脚本来轻松生成派生页面类。并且没有一大堆代表和东西被传递,我发现新开发人员很难理解。