设置了属性,不知道是哪个
Setting the propery, when not knowing which one
比如说我有这个 class 和一些成员,例如(这是一个人为的例子,我不想讨论现实生活中设计的复杂性。我真的只是想在此传达总体思路。):
public class Address
{
public Guid Id { get; set; }
public Guid? HouseId { get; set; }
public Guid? FlatId { get; set; }
public Guid? SomeOtherBuildingTypeId { get; set;
}
现在碰巧有 3 种创建地址的方法:
public void CreateAddressForHouse();
public void CreateAddressForFlat();
public void CreateAddressForSomeOtherBuildingType();
从表面上看,这组方法做的是完全相同的事情,只是在地址 class 中设置了不同的 ID 属性。这在现实生活中的应用程序中造成了相当多的代码重复,我想将其重写为更通用的内容。
在我看来,我可以将所需 属性 的名称及其值传递给 CreateAddress 函数,类似于 Func。但是我在这方面严重缺乏,从哪里开始呢?我可以立即使用哪些 .NET 内容?或者我应该寻找哪些特定关键字?
您可以使用 MemberExpression:
public void CreateAddress(Expression<Func<Address, Guid?>> member)
{
// Get the property from the expression
var propertyInfo = GetPropertyInfo(this, member);
// Create a new address
var guid = Guid.NewGuid();
// Assign it to the property of this instance
propertyInfo.SetValue(this, guid);
}
然后你调用这个方法,使用 lambda a => a.PropertyName
:
var address = new Address();
address.CreateAddress(a => a.HouseId);
Console.WriteLine(address.HouseId);
有关 GetPropertyInfo
的实施,请参阅 Retrieving Property name from lambda expression。它获取 lambda 表达式中指定成员的 PropertyInfo
(并检查它确实是一个 属性),您可以使用它来设置 CreateAddress
中的 属性方法。
除此之外, 是有效的。也许你不应该为每个地址类型使用 属性,而应该使用 Dictionary<AddressType, Guid?>
属性。这可能可行也可能不可行,具体取决于 class 设计及其预期用途。
您可以使用表达式树来简化您的问题:
public class AddressService
{
public Address CreateAddress(Expression<Func<Address, Guid?>> idPropertySelector)
{
// So you get the property info to later set it using reflection
MemberExpression propertyExpr = (MemberExpression)idPropertySelector.Body;
PropertyInfo property = (PropertyInfo)propertyExpr.Member;
// Then you create an instance of address...
Address address = new Address();
// and you set the property using reflection:
property.SetValue(address, (Guid?)Guid.NewGuid());
return address;
}
}
现在,谁知道您的代码中的哪个位置会起作用:
AddressService service = new AddressService();
Address address = service.CreateAddress(a => a.FlatId);
Guid? flatId = address.FlatId; // This will be already assigned!
您可以按照 Corak 的建议添加 属性 BuildingType BuildingType 作为枚举 BuildingType { House, Flat, SomeOtherBuildingType, YetAnotherThing } 的值。
为了更简单,可以在Address class:
中创建参数化构造函数
public Address(Guid? id,BuildingType type)
{
switch(type)
{
case BuildingType.House:
HouseId=id;
break;
case BuildingType.Flat:
FlatId=id;
break;
case BuildingType.SomeOtherBuildingType:
SomeOtherBuildingTypeId =id;
break;
default:
break;
}
}
这样扩展起来会更容易。
另外,您不需要有那么多方法。只用一个CreateAddress()就可以生成多种类型的地址。
比如说我有这个 class 和一些成员,例如(这是一个人为的例子,我不想讨论现实生活中设计的复杂性。我真的只是想在此传达总体思路。):
public class Address
{
public Guid Id { get; set; }
public Guid? HouseId { get; set; }
public Guid? FlatId { get; set; }
public Guid? SomeOtherBuildingTypeId { get; set;
}
现在碰巧有 3 种创建地址的方法:
public void CreateAddressForHouse();
public void CreateAddressForFlat();
public void CreateAddressForSomeOtherBuildingType();
从表面上看,这组方法做的是完全相同的事情,只是在地址 class 中设置了不同的 ID 属性。这在现实生活中的应用程序中造成了相当多的代码重复,我想将其重写为更通用的内容。
在我看来,我可以将所需 属性 的名称及其值传递给 CreateAddress 函数,类似于 Func。但是我在这方面严重缺乏,从哪里开始呢?我可以立即使用哪些 .NET 内容?或者我应该寻找哪些特定关键字?
您可以使用 MemberExpression:
public void CreateAddress(Expression<Func<Address, Guid?>> member)
{
// Get the property from the expression
var propertyInfo = GetPropertyInfo(this, member);
// Create a new address
var guid = Guid.NewGuid();
// Assign it to the property of this instance
propertyInfo.SetValue(this, guid);
}
然后你调用这个方法,使用 lambda a => a.PropertyName
:
var address = new Address();
address.CreateAddress(a => a.HouseId);
Console.WriteLine(address.HouseId);
有关 GetPropertyInfo
的实施,请参阅 Retrieving Property name from lambda expression。它获取 lambda 表达式中指定成员的 PropertyInfo
(并检查它确实是一个 属性),您可以使用它来设置 CreateAddress
中的 属性方法。
除此之外,Dictionary<AddressType, Guid?>
属性。这可能可行也可能不可行,具体取决于 class 设计及其预期用途。
您可以使用表达式树来简化您的问题:
public class AddressService
{
public Address CreateAddress(Expression<Func<Address, Guid?>> idPropertySelector)
{
// So you get the property info to later set it using reflection
MemberExpression propertyExpr = (MemberExpression)idPropertySelector.Body;
PropertyInfo property = (PropertyInfo)propertyExpr.Member;
// Then you create an instance of address...
Address address = new Address();
// and you set the property using reflection:
property.SetValue(address, (Guid?)Guid.NewGuid());
return address;
}
}
现在,谁知道您的代码中的哪个位置会起作用:
AddressService service = new AddressService();
Address address = service.CreateAddress(a => a.FlatId);
Guid? flatId = address.FlatId; // This will be already assigned!
您可以按照 Corak 的建议添加 属性 BuildingType BuildingType 作为枚举 BuildingType { House, Flat, SomeOtherBuildingType, YetAnotherThing } 的值。 为了更简单,可以在Address class:
中创建参数化构造函数public Address(Guid? id,BuildingType type)
{
switch(type)
{
case BuildingType.House:
HouseId=id;
break;
case BuildingType.Flat:
FlatId=id;
break;
case BuildingType.SomeOtherBuildingType:
SomeOtherBuildingTypeId =id;
break;
default:
break;
}
}
这样扩展起来会更容易。 另外,您不需要有那么多方法。只用一个CreateAddress()就可以生成多种类型的地址。