2010-03-27 74 views
2

我来自ColdFusion中的背景,并最终转向现代的东西,所以请耐心等待。在C#中铸造对象(ASP.Net MVC)

我遇到了铸造对象的问题。我有两个数据库表,我用它们作为模型 - 住宅和商业。他们都分享他们的大部分领域,尽管每个领域都有一些独特的领域。我创建了另一个类作为包含所有属性字段总和的容器。查询住宅和商业,将其放入我的容器中,狡猾地称为Property。这工作正常。

但是,我遇到了从住宅/商业到房地产的混淆问题。为每个属性创建一个方法非常简单:fillPropertyByResidential(Residential source)和fillPropertyByCommercial(Commercial source),并为变量生成别名。这也可以正常工作,但显然会复制一堆代码 - 所有那些在两个主要模型之间共享的字段。

所以,我想要一个通用的fillPropertyBySource()接受对象,并检测它是Residential还是Commercial,填充每个类型的特定字段,然后执行所有的字段。除此之外,我在C#中收集的内容是在if内创建的变量仅在if的范围内,所以我不确定如何执行此操作。

public property fillPropertyBySource(object source) 
    { 
     property prop = new property(); 
     if (source is Residential) 
     { 
      Residential o = (Residential)source; 
      //Fill Residential only fields 

     } 
     else if (source is Commercial) 
     { 
      Commercial o = (Commercial)source; 
      //Fill Commercial only fields 
     } 
     //Fill fields shared by both 
     prop.price = (int)o.price; 
     prop.bathrooms = (float)o.bathrooms; 

     return prop; 
    } 

作为商业或住宅的“o”只存在于if的范围内。如何检测源对象的原始类型并采取措施?

忍无可忍 - 从ColdFusion转变为现代语言相当困难。更多的是因为我习惯了程序代码,MVC是一个巨大的范式转变。

编辑:我应该包含错误:名称'o'在当前上下文中不存在 对于共享区域中价格和浴室的别名。

回答

1

由于通过使用数据库生成的对象类型而不是分层定义的对象类型强加给您的人为约束,实际上没有优雅的解决方案。我可以提供最好的解决方案是使用部分类附加一个已知的接口,然后使用重载做的工作的最小量所需复制的对象时:

interface IPropertyBase 
{ 
    decimal Price { get; set; } 
    int Bathrooms { get; set; } 
} 

partial class Residential : IPropertyBase 
{ 
} 

partial class Commercial : IPropertyBase 
{ 
} 

class Property : IPropertyBase 
{ 
public decimal Price { get; set; } 
public int Bathrooms { get; set; } 

    // Commercial 
    public int Offices { get; set; } 

    // Residential 
    public int Bedrooms { get; set; } 

    private void CopyFromBase(IPropertyBase o) 
    { 
     Price = o.Price; 
     Bathrooms = o.Bathrooms; 
    } 

    public void CopyFrom(Commercial o) 
    { 
     CopyFromBase(o); 

     Offices = o.Offices; 
    } 

    public void CopyFrom(Residential o) 
    { 
     CopyFromBase(o); 

     Bedrooms = o.Bedrooms; 
    } 
} 

作为一般的笔记,“联盟”对象这种类型往往是一个坏主意。您最好在IPropertyBase界面中定义常用属性,并在您处理它们时将Residential/Commercial对象保留为“本机”形式。例如,如果您需要创建一个区域中所有属性的组合集合,请创建一个List<IPropertyBase>并直接使用它 - 它将保持列表中的对象完好(允许您稍后使用is /作为运算符,如果你需要的话),它不会在每个对象上产生大量空的,无意义的字段。

+0

@丹 - 非常感谢。这将我在Controller中的逻辑回归到它所属的模型中。很棒! – Mortanis

4

这是最好的,像这样的接口实现:

public interface IProperty 
{ 
    int price { get; set; } 
    float bathrooms { get; set; } 
} 

public class Residential : IProperty 
{ 
    public int price { get; set; } 
    public float bathrooms { get; set; } 
    //Other stuff... 
} 

public class Commercial : IProperty 
{ 
    public int price { get; set; } 
    public float bathrooms { get; set; } 
    //Other stuff... 
} 

然后在你的方法,把接口而不是对象:

public property fillPropertyBySource(IProperty source) 
{ 
    property prop = new property(); 
    if (source is Residential) 
    { 
     Residential o = (Residential)source; 
     //Fill Residential only fields 

    } 
    else if (source is Commercial) 
    { 
     Commercial o = (Commercial)source; 
     //Fill Commercial only fields 
    } 
    //Fill fields shared by both 
    prop.price = source.price; 
    prop.bathrooms = source.bathrooms; 

    return prop; 
} 

当你的类具有共同属性的接口使用你想访问。你也可以有一个基类Propertypricebathrooms并从中继承,而不管你喜欢什么。

+0

我错过了什么,尼克?看起来这仍然会推出超出范围的参考例外...?不过,绝对同意接口方法。 –

+1

@Gus - Woops错过了那些变量的重命名,修复! –

+0

恐怕我没跟着。通过Linq To SQL处理直接从数据库中生成住宅和商业。我在代码中实际上没有他们的类定义。数据库包含像“浴室”和“价格”这样的字段,这就是我需要从源对象获取到我手动制作的“属性”类中的属性,该属性也包含所有这些字段,我打算用这些字段填充数据住宅或商业。 我不知道如何将接口添加到的LINQ to SQL生成的模型,但住宅和商业已经有浴室和价格领域。 – Mortanis