有没有办法向 C# 中的对象添加 key/value 语法?
Is there a way to add key/value syntax to an object in C#?
我有一个名为 CottonCandy 的对象。 CottonCandy 有几个属性:
- 质量
- 音量
- 总糖
- 颜色
如果我可以向 CottonCandy 添加一些东西以便我可以像这样检索属性,那就太好了:
var colors = cottonCandy["Colors"];
从阅读 this 看来,您可以通过以下方式获取值:
cottonCandy.GetType().GetProperty("Colors").GetValue(cottonCandy, null);
您可以轻松地将其包装在一个方法中:
var colors = cottonCandy.GetPropertyValue("Colors");
但我真的更喜欢 key/value 语法 cottonCandy["Colors"]
。有什么办法可以实现吗?
如果您的 class 是一个简单的数据对象,没有任何行为,只有这么简单的属性,您可以将其设为 Dictionary
:
var map = new Dictionary<string, whatever> { { "Colors", ... }, { "Mass", ... } ... };
map["Colors"] = ...;
否则你应该像你已经提到的那样使用反射。
这不是 key/vaue 语法。但是,如果您决定使用扩展,则可以使用此扩展方法。此 Nuget 包
中有类似的扩展
public static T GetFieldValue<T>(this object obj, string fieldName)
{
T result;
PropertyInfo propertyInfo = obj.GetType().GetProperty(fieldName);
if (propertyInfo != null)
{
result = (T)propertyInfo.GetValue(obj);
}
else
{
throw new FieldAccessException($"{fieldName} cannot be found");
}
return result;
}
您可以通过 this link. Maybe unit tests 提供有关方法使用和结果的线索来获得更多扩展。
更新:
您可以像这样组合扩展方法和索引器:
public class TestClass
{
public string this[string field]
{
get => this.GetFieldValue<string>(field);
set => this.TrySetFieldValue(field, value);
}
}
其实是有办法的。您可以使用 indexers。但是您需要具有相同的字段类型或将值装在 object
类型中。
class CottonCandy
{
private int Mass { get; set; }
private int Volume { get; set; }
private int TotalSugar { get; set; }
private int Colors { get; set; }
public int this[string field]
{
get
{
PropertyInfo propertyInfo = typeof(CottonCandy).GetProperty(field);
if(propertyInfo == null)
throw new ArgumentException("Invalid field");
return (int)propertyInfo.GetValue(this);
}
}
}
尝试查看对象索引器:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/
实现此目的的一种方法是使用索引器并使用 "nameof" 运算符将索引器字符串值与可用属性进行比较。这会使代码更加冗长,但避免了反射的需要。
但是,请确保这确实是您真正想要的,因为如果您以这种方式访问属性,您将不再获得编译时检查的好处。
你可以做到这一点
public class CottonCandy
{
public string Mass { get; set; }
public string Volume { get; set; }
public string TotalSugar { get; set; }
public string Colors { get; set; }
public string this[string key]
{
get
{
switch (key)
{
case "Mass":
return this.Mass;
case "Volume":
return this.Volume;
case "TotalSugar":
return this.TotalSugar;
case "Colors":
return this.Colors;
default:
return "";
}
}
set
{
switch (key)
{
case "Mass":
this.Mass = value; break;
case "Volume":
this.Volume = value; break;
case "TotalSugar":
this.TotalSugar = value; break;
case "Colors":
this.Colors = value; break;
default:
break;
}
}
}
}
我有一个名为 CottonCandy 的对象。 CottonCandy 有几个属性:
- 质量
- 音量
- 总糖
- 颜色
如果我可以向 CottonCandy 添加一些东西以便我可以像这样检索属性,那就太好了:
var colors = cottonCandy["Colors"];
从阅读 this 看来,您可以通过以下方式获取值:
cottonCandy.GetType().GetProperty("Colors").GetValue(cottonCandy, null);
您可以轻松地将其包装在一个方法中:
var colors = cottonCandy.GetPropertyValue("Colors");
但我真的更喜欢 key/value 语法 cottonCandy["Colors"]
。有什么办法可以实现吗?
如果您的 class 是一个简单的数据对象,没有任何行为,只有这么简单的属性,您可以将其设为 Dictionary
:
var map = new Dictionary<string, whatever> { { "Colors", ... }, { "Mass", ... } ... };
map["Colors"] = ...;
否则你应该像你已经提到的那样使用反射。
这不是 key/vaue 语法。但是,如果您决定使用扩展,则可以使用此扩展方法。此 Nuget 包
中有类似的扩展public static T GetFieldValue<T>(this object obj, string fieldName)
{
T result;
PropertyInfo propertyInfo = obj.GetType().GetProperty(fieldName);
if (propertyInfo != null)
{
result = (T)propertyInfo.GetValue(obj);
}
else
{
throw new FieldAccessException($"{fieldName} cannot be found");
}
return result;
}
您可以通过 this link. Maybe unit tests 提供有关方法使用和结果的线索来获得更多扩展。
更新:
您可以像这样组合扩展方法和索引器:
public class TestClass
{
public string this[string field]
{
get => this.GetFieldValue<string>(field);
set => this.TrySetFieldValue(field, value);
}
}
其实是有办法的。您可以使用 indexers。但是您需要具有相同的字段类型或将值装在 object
类型中。
class CottonCandy
{
private int Mass { get; set; }
private int Volume { get; set; }
private int TotalSugar { get; set; }
private int Colors { get; set; }
public int this[string field]
{
get
{
PropertyInfo propertyInfo = typeof(CottonCandy).GetProperty(field);
if(propertyInfo == null)
throw new ArgumentException("Invalid field");
return (int)propertyInfo.GetValue(this);
}
}
}
尝试查看对象索引器:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/
实现此目的的一种方法是使用索引器并使用 "nameof" 运算符将索引器字符串值与可用属性进行比较。这会使代码更加冗长,但避免了反射的需要。
但是,请确保这确实是您真正想要的,因为如果您以这种方式访问属性,您将不再获得编译时检查的好处。
你可以做到这一点
public class CottonCandy
{
public string Mass { get; set; }
public string Volume { get; set; }
public string TotalSugar { get; set; }
public string Colors { get; set; }
public string this[string key]
{
get
{
switch (key)
{
case "Mass":
return this.Mass;
case "Volume":
return this.Volume;
case "TotalSugar":
return this.TotalSugar;
case "Colors":
return this.Colors;
default:
return "";
}
}
set
{
switch (key)
{
case "Mass":
this.Mass = value; break;
case "Volume":
this.Volume = value; break;
case "TotalSugar":
this.TotalSugar = value; break;
case "Colors":
this.Colors = value; break;
default:
break;
}
}
}
}