什么';在C#中,将值类型更改为引用类型的最佳方法是什么?
我有三类定义如下:什么';在C#中,将值类型更改为引用类型的最佳方法是什么?,c#,entity-framework,reference,C#,Entity Framework,Reference,我有三类定义如下: public class Base { public int Id { get; set; } } public class Bar : Base { ... } public class Foo : Base { public int? ParentId { get; set; } public Base Parent { get; set; } public int? FooParentId { get; set; } pub
public class Base
{
public int Id { get; set; }
}
public class Bar : Base { ... }
public class Foo : Base
{
public int? ParentId { get; set; }
public Base Parent { get; set; }
public int? FooParentId { get; set; }
public Foo FooParent { get; set; }
public int? BarParentId { get; set; }
public Bar BarParent { get; set; }
public Foo(Foo parent)
{
FooParent = parent;
FooParentId = parent.Id;
Parent = FooParent; // Now changes to Parent are reflected on FooParent
ParentId = FooParentId; // Changes to ParentId are not reflected because it is a value type.
}
public Foo(Bar parent)
{
// Same implementation as ctor(Foo parent);
}
}
我试图做的是让Parent
引用FooParent
或BarParent
(我认为这相当简单),然后让ParentId
引用FooParentId
或BarParentId
。使ParentId
成为引用类型的最明智的方法是什么
答案提到整数的装箱/拆箱有很多相关问题。这真的是一个糟糕的解决方案吗 编辑:
我应该提到
Foo
和Bar
是实体框架表Foo
是一个对象,它可能是一个表或另一个表的子对象,要使实体框架代码首先正确生成表,必须同时定义FooParent
和BarParent
。另外,ParentId
在其getter中可能不会引用Parent
。实体框架也应该为此负责。调用context.Set().Add(newItem)时的实体框架代码>。将重新插入所有非空的父对象。因为您已经有了对父对象的引用,所以可以使用以下属性获取其Id:
public int? ParentId
{
get
{
return Parent != null ? Parent.Id : null;
}
}
您可以向FooParentId
和BarParentId
属性的get
和set
访问器添加逻辑,但同意@Servy的观点,即这是一个糟糕的设计
原因甚至不仅仅是ID-s和对对象的引用。我不明白为什么您需要同时拥有BarParent和FooParent,只需要拥有一个类型为IParent
的属性,然后使用此接口提供的方法与之通信,利用继承和多态性的所有好处。如果您的手被EF束缚,您可以使用委托根据构造函数中传递的类型传播父ID的更改。我不知道EF是否会对此抱怨
例如,使用操作
委托,我们可以将对父ID
的更改转发到相应的[Foo | Bar]ParentId
:
public class Base
{
public int Id { get; set; }
}
public class Bar : Base { }
public class Foo : Base
{
private int? _parentId;
public int? ParentId {
get{ return _parentId; }
set{
_parentId = value;
if( OnParentChangeAction != null ) {
OnParentChangeAction( _parentId );
}
}
}
public Base Parent { get; set; }
public int? FooParentId { get; set; }
public Foo FooParent { get; set; }
public int? BarParentId { get; set; }
public Bar BarParent { get; set; }
private Action<int?> OnParentChangeAction{ get; set; }
public Foo(Foo parent)
{
FooParent = parent;
FooParentId = parent.Id;
Parent = FooParent;
ParentId = FooParentId;
OnParentChangeAction = newParentId => FooParentId = newParentId;
}
public Foo(Bar parent)
{
BarParent = parent;
BarParentId = parent.Id;
Parent = BarParent;
ParentId = BarParentId;
OnParentChangeAction = newParentId => BarParentId = newParentId;
}
}
公共类基
{
公共int Id{get;set;}
}
公共类栏:基{}
公共类Foo:Base
{
private int?\u parentId;
公共int?父ID{
获取{return\u parentId;}
集合{
_parentId=值;
if(OnParentChangeAction!=null){
OnParentChangeAction(_parentId);
}
}
}
公共基父项{get;set;}
public int?FooParentId{get;set;}
公共Foo foopparent{get;set;}
公共int?BarParentId{get;set;}
公共条BarParent{get;set;}
ParentChangeAction{get;set;}上的私有操作
公共Foo(Foo家长)
{
FooParent=父;
FooParentId=parent.Id;
父母=父母;
ParentId=FooParentId;
OnParentChangeAction=newParentId=>FooParentId=newParentId;
}
公共食品(酒吧家长)
{
BarParent=父母;
BarParentId=parent.Id;
家长=家长;
ParentId=BarParentId;
OnParentChangeAction=newParentId=>BarParentId=newParentId;
}
}
您需要花一些时间阅读值类型(不是primative,它们被称为值类型)和引用类型。将引用更改为指向新引用会更改该变量的值,并且不会影响引用旧引用的任何其他变量。你不是在改变引用,而是在改变变量以引用一个新实例。同时保留对象的整数ID和对象本身似乎也是一个糟糕的设计。如果需要,对象本身有自己的ID值,就像对象的ID一样,而不是保留副本。难道不能让属性委托给相应的属性吗<代码>公共int?ParentId{get{return Parent!=null?Parent.Id:(int?)null;}}
@Servy我同意,这是一个糟糕的设计。但是,我使用的是EntityFramework,需要修复EntityFramework中的另一个设计缺陷。如果您感兴趣,请解释。这是一个很好的建议,但不幸的是,它对我不起作用。实体框架要求父ID与父引用解耦。这里有更详细的解释,你在这里看到的是一个概念上的事件。您会发现最好使用C#事件
来模拟概念事件,而不是将委托作为属性。如果您不使用事件提供的任何功能(如多播),为什么“最好”使用事件
?如果这是一个公开的属性,我会同意,但这是一个私有成员,事件
是一个滥杀。多播不是事件
的属性,而是代理的属性。C#中的所有代理都是多播代理。您在那里使用的代理是多播代理。使用事件
的主要原因之一是,代码在语义上与您的需求相似。当代码更有效地表达其含义时,其他人就更容易理解它。以多播方式使用标准委托的情况非常罕见。事件提供的发布者/订阅者语义在仅限于声明类型时没有意义。更不用说活动所需的所有仪式了。您需要创建一个EventArgs
类来将数据传递给处理程序。您需要包括发送方
,即使它都在声明类型中。我想我们必须同意不同意。不,你不需要做这两件事。更改的范围是将行的声明更改为:private event Action ParentChanged代码>完成。最好将事件订阅从=