C# 设置属性,但不知道是哪一个
例如,假设我有几个成员参加了这门课(这是一个人为的例子,我不想讨论现实生活中复杂的设计。我真的只想在这里传达一般的想法。): 现在,有3种方法可以创建地址:C# 设置属性,但不知道是哪一个,c#,generics,reflection,C#,Generics,Reflection,例如,假设我有几个成员参加了这门课(这是一个人为的例子,我不想讨论现实生活中复杂的设计。我真的只想在这里传达一般的想法。): 现在,有3种方法可以创建地址: public void CreateAddressForHouse(); public void CreateAddressForFlat(); public void CreateAddressForSomeOtherBuildingType(); 在表面之下,这组方法做了完全相同的事情,在Address类中设置不同的Id属性。这会在实
public void CreateAddressForHouse();
public void CreateAddressForFlat();
public void CreateAddressForSomeOtherBuildingType();
在表面之下,这组方法做了完全相同的事情,在Address类中设置不同的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);
}
有关GetPropertyInfo
的实现,请参阅。它获取lambda表达式中指定的成员的PropertyInfo
(并检查它是否确实是一个属性),您可以使用它在CreateAddress
方法中设置属性
除此之外,这是一个有效的。也许您不应该使用每个地址类型的属性,而应该使用
字典
属性。这可能可行,也可能不可行,具体取决于类设计及其预期用途。您可以使用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);
}
有关GetPropertyInfo
的实现,请参阅。它获取lambda表达式中指定的成员的PropertyInfo
(并检查它是否确实是一个属性),您可以使用它在CreateAddress
方法中设置属性
除此之外,这是一个有效的。也许您不应该使用每个地址类型的属性,而应该使用
字典
属性。这可能可行,也可能不可行,取决于类设计及其预期用途。您可以使用表达式树来简化问题:
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;
}
}
可以使用表达式树简化问题:
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;
}
}
您可以按照Corak的建议添加属性BuildingType BuildingType作为enum BuildingType{House,Flat,SomeOtherBuildingType,YetAnotherThing}的值。 为了简化,您可以在Address类中创建参数化构造函数:
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()来生成多种类型的地址。您可以添加属性BuildingType BuildingType,该属性是Corak建议的enum BuildingType{House,Flat,SomeOtherBuildingType,YetAnotherThing}的值。 为了简化,您可以在Address类中创建参数化构造函数:
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()来生成多种类型的地址。将方法所做的一切“完全相同”打包到一个单独的方法
CreateAddress()
(可能是private
)中,然后从这三个方法调用它?或者更好的是,有一个Guid BuildingTypeID
和一个BuildingType BuildingType
作为enum BuildingType{House,Flat,SomethingElse,YetAnotherThing}
的值,这似乎比每种新类型的建筑的新属性都灵活得多。我对每种类型的属性都不满意,这是一些表中有大量可为空的FK的结果:(将方法所做的一切“完全相同”打包到一个单独的方法CreateAddress()
(可能是private
)从这三个方法中调用它?或者更好,让一个Guid BuildingTypeID
和一个BuildingType BuildingType
作为enum BuildingType{House,Flat,SomethingElse,YetAnotherThing}的值
,对于每种新类型的建筑,它似乎比新属性灵活得多。我对每种类型的属性都不满意,这是因为有些表中有许多可为空的FK:(当使用a=>new Guid()调用时,将抛出此((MemberExpression)idPropertySelector.Body
)(或者基本上不是MemberExpression的任何内容)@CodeCaster有时我觉得答案不应该适合所有的用例,也不应该关注所有的副作用。归根结底,我们不是一个编码服务……如果OP得到了这个想法,那就足够了。你的意见是什么?你完全正确。我们不必提供傻瓜式的、可复制的粘贴代码。我只是把它作为一个警告来评论。这是code不是用户友好的,也不应该按原样使用(至少,如果您在错误使用代码时关心(重新)可用性和相关异常)。但这适用于大多数代码,所以::-)这个表达式api非常好。应该研究一下:)@CodeCaster认为防弹代码应该放在某个GitHub存储库中,或者谁知道呢。至少对我来说,一天结束时,还有一些想法可以帮助我了解更多关于某个主题的方向。我不喜欢提供包含所有细节的完整解决方案,因为你需要一些挑战来超越你自己的知识和技能,然后复制粘贴解决方案不适用于此((MemberExpression)idPropertySelector.Body
)在使用a=>new Guid()
(或者基本上不是MemberExpression的任何内容)调用时将抛出@CodeCaster有时我觉得答案不应该适合所有的用例,也不应该关注所有的副作用。归根结底,我们不是一个编码服务……如果OP得到了这个想法,那就足够了。你的意见是什么?你完全正确。我们不必提供傻瓜式的、可复制的粘贴代码。我只是把它作为一个警告来评论。这是code不是用户友好的,也不应该按原样使用(至少,如果您在错误使用代码时关心(重新)可用性和相关异常),但这适用于大多数代码,所以::-)这个表达式api非常好。应该研究以下内容:)@CodeCaster防弹代码