เป็นไปได้หรือไม่ที่จะมีสองคลาสบางส่วนในแอสเซมบลีที่ต่างกันแสดงคลาสเดียวกันได้หรือไม่?


128

ฉันมีคลาสที่เรียกว่า 'บทความ' ในโครงการที่ชื่อว่า 'MyProject.Data' ซึ่งทำหน้าที่เป็นชั้นข้อมูลสำหรับเว็บแอปพลิเคชันของฉัน

ฉันมีโครงการแยกต่างหากชื่อ 'MyProject.Admin' ซึ่งเป็นระบบการดูแลระบบบนเว็บสำหรับการดู / แก้ไขข้อมูลและสร้างโดยใช้ ASP.NET Dynamic Data

โดยทั่วไปฉันต้องการขยายคลาส Article โดยใช้คลาสบางส่วนเพื่อให้ฉันสามารถเพิ่มคุณสมบัติอย่างใดอย่างหนึ่งด้วยส่วนขยาย "UIHint" ซึ่งจะทำให้ฉันสามารถแทนที่กล่องข้อความแบบหลายบรรทัดปกติด้วยการควบคุม FCKEdit

ชั้นบางส่วนและส่วนขยายของฉันจะมีลักษณะเช่นนี้:

[MetadataType(typeof(ProjectMetaData))]
public partial class Project
{
}

public class ProjectMetaData
{
    [UIHint("FCKeditor")]
    public object ItemDetails { get; set; }
}

ตอนนี้ทั้งหมดทำงานได้ดีถ้าคลาสบางส่วนอยู่ในโครงการเดียวกันกับคลาสบางส่วนดั้งเดิม - เช่นโครงการ MyProject.Data

แต่พฤติกรรมของ UI ไม่ควรอยู่ในชั้นข้อมูล แต่ควรอยู่ในชั้นผู้ดูแลระบบ ดังนั้นฉันต้องการย้ายคลาสนี้ไปที่ MyProject.Admin

อย่างไรก็ตามถ้าฉันทำเช่นนั้นฟังก์ชั่นจะหายไป

คำถามพื้นฐานของฉันคือ: ฉันสามารถมี 2 ส่วนบางส่วนในโครงการที่แยกต่างหาก แต่ทั้งสองอ้างถึง "ชั้น" เดียวกันได้หรือไม่

ถ้าไม่มีมีวิธีที่จะทำให้สิ่งที่ฉันพยายามทำได้สำเร็จโดยไม่ต้องผสมตรรกะของเลเยอร์ข้อมูลกับตรรกะ UI หรือไม่


1
นี่คือเหตุผลที่แนวคิดของ MetadataType เหม็น ( en.wikipedia.org/wiki/Code_smell ) มันเป็นโซลูชั่นที่สมบูรณ์แบบ - คุณพยายามสร้าง MVC ซึ่งแยกโมเดลจากมุมมองจากคอนโทรลเลอร์และคุณต้องการตรรกะมุมมองและการตรวจสอบความถูกต้องในคลาสข้อมูล ไร้สาระ ควรมีวิธีที่ดีกว่าในการใช้คุณลักษณะเหล่านี้ คุณควรจะสามารถเชื่อมโยงคลาสข้อมูลเมตากับคลาสข้อมูลโดยใช้ API ได้อย่างคล่องแคล่วหรือสิ่งที่คล้ายกัน ไม่ควรนำเข้าอบ
Jim

คำตอบอื่น ๆ พูดถึงสิ่งนี้: หากเป็นสิ่งจำเป็นอย่างยิ่งและคุณเป็นเจ้าของแหล่งอ้างอิงแอสเซมบลีคุณสามารถรวมรุ่นแหล่งที่มาเป็นไฟล์ที่เชื่อมโยง (ปุ่มแยกบนตัวเลือกไฟล์ Add-Existing-Item) เพื่อสร้างด้วย การบริโภคแทนการอ้างอิงการชุมนุม (กลยุทธ์ที่คล้ายคลึงกันในการเปิดเผย Model / Data layer ของคุณผ่าน WCF พร้อมด้วย Service Reference และการขยายคลาสที่สร้างรหัสบางส่วน) คุณไม่เคยถูกบังคับให้ชนเลเยอร์ - คุณสามารถคลาสย่อยได้เสมอ และMetadataTypeทำให้แบบจำลองมากขึ้นเช่น ViewModels
JoeBrockhaus

มันสายเกินไปที่จะตอบสนอง แต่ฉันได้เตรียมวิธีแก้ปัญหาไว้ที่นี่
Usman

ฉันรู้ว่ามันสายเกินไปที่จะตอบสนอง แต่ที่นี่ฉันได้นำเสนอวิธีแก้ปัญหา
Usman

คำตอบ:


178

ไม่คุณไม่สามารถมีคลาสบางส่วนที่อ้างถึงคลาสเดียวกันในแอสเซมบลีที่ต่างกันสองโครงการ (โปรเจ็กต์) เมื่อรวบรวมแอสเซมบลีแล้ว meta-data จะถูกอบเข้าและคลาสของคุณจะไม่ถูกแยกออก คลาสบางส่วนช่วยให้คุณสามารถแยกคำจำกัดความของคลาสเดียวกันออกเป็นสองไฟล์


15

ตามที่ระบุไว้คลาสบางส่วนเป็นปรากฏการณ์เวลารวบรวมไม่ใช่ runtime คลาสในชุดประกอบเสร็จสมบูรณ์โดยคำจำกัดความ

ในแง่ MVC คุณต้องการแยกรหัสมุมมองออกจากรหัสรุ่น แต่เปิดใช้งาน UI บางประเภทตามคุณสมบัติของรุ่น ตรวจสอบภาพรวมที่ยอดเยี่ยมของ Martin Fowler เกี่ยวกับรสชาติที่แตกต่างของ MVC, MVP และอะไร: คุณจะพบแนวคิดการออกแบบมากมาย ฉันคิดว่าคุณสามารถใช้Dependency Injectionเพื่อบอก UI ว่าการควบคุมแบบใดที่ใช้ได้กับเอนทิตีและคุณลักษณะแต่ละรายการ

เป้าหมายของคุณในการแบ่งแยกข้อกังวลนั้นยอดเยี่ยม แต่คลาสบางส่วนมีจุดประสงค์เพื่อแก้ไขปัญหาที่แตกต่างกันโดยสิ้นเชิง


8

วิธีการขยายและ ViewModels เป็นวิธีมาตรฐานในการขยายวัตถุเลเยอร์ข้อมูลในส่วนหน้าดังนี้:

ชั้นข้อมูล (ไลบรารีคลาส Person.cs):

namespace MyProject.Data.BusinessObjects
{
  public class Person
  {
    public string Name {get; set;}
    public string Surname {get; set;}
    public string Details {get; set;}
  }
}

Display Layer (เว็บแอปพลิเคชัน) PersonExtensions.cs:

using Data.BusinessObjects
namespace MyProject.Admin.Extensions
{
  public static class PersonExtensions
  {
    public static HtmlString GetFormattedName(this Person person)
    {
       return new HtmlString(person.Name + " <b>" + person.Surname</b>);
    }
  }
}

ViewModel (สำหรับข้อมูลเฉพาะการดูเพิ่มเติม):

using Data.BusinessObjects
namespace MyProject.Admin.ViewModels
{
  public static class PersonViewModel
  {
    public Person Data {get; set;}
    public Dictionary<string,string> MetaData {get; set;}

    [UIHint("FCKeditor")]
    public object PersonDetails { get { return Data.Details; } set {Data.Details = value;} }
  }
}

ตัวควบคุม PersonController.cs:

public ActionMethod Person(int id)
{
  var model = new PersonViewModel();
  model.Data = MyDataProvider.GetPersonById(id);
  model.MetaData = MyDataProvider.GetPersonMetaData(id);

  return View(model);
}

ดู, Person.cshtml:

@using MyProject.Admin.Extensions

<h1>@Model.Data.GetFormattedName()</h1>
<img src="~/Images/People/image_@(Model.MetaData["image"]).png" >
<ul>
  <li>@Model.MetaData["comments"]</li>
  <li>@Model.MetaData["employer_comments"]</li>
</ul>
@Html.EditorFor(m => m.PersonDetails)

ความคิดเห็นส่วนขยายทำให้รู้สึกค่อนข้างนี้สามารถแยกออกอย่างสมบูรณ์จากวัตถุบุคคลโดยใช้อินเตอร์เฟซ ฉันชอบมัน!
Pale Ale

2

เพิ่มไฟล์ฐานเป็นไฟล์ที่ลิงก์ในโครงการของคุณ ยังคงเป็นบางส่วน แต่ให้คุณแชร์ระหว่างโครงการทั้งสองให้ซิงโครไนซ์และในขณะเดียวกันก็มีรหัสเฉพาะเวอร์ชัน / กรอบงานในคลาสบางส่วน


1

ฉันมีปัญหาที่คล้ายกันกับสิ่งนี้ ฉันเก็บคลาสบางส่วนของฉันไว้ในโครงการ Data ของฉันดังนั้นในกรณีของคุณคือ 'MyProject.Data' MetaDataClasses ไม่ควรไปในโครงการผู้ดูแลระบบของคุณเพราะคุณจะสร้างการอ้างอิงแบบวงกลมอย่างชาญฉลาด

ฉันได้เพิ่มโครงการ Class Lib ใหม่สำหรับ MetaDataClasses ของฉันเช่น 'MyProject.MetaData' จากนั้นอ้างอิงโครงการนี้จากโครงการข้อมูลของฉัน


1

อาจใช้คลาสส่วนขยายแบบคงที่


ความคิดที่ดี. คุณช่วยยกตัวอย่างสิ่งที่คุณคิดว่าจะให้ฟังก์ชั่นที่เพียงพอภายในคำตอบของคุณ
pvanhouten

0

ฉันอาจเข้าใจผิดที่นี่ แต่คุณไม่สามารถกำหนดคลาส ProjectMetaData ในโครงการ MyProject.Admin ของคุณได้หรือไม่?


0

เพียงเพิ่มไฟล์คลาสเป็นลิงค์ในโปรเจ็กต์ใหม่ของคุณและเก็บเนมสเปซเดียวกันไว้ในคลาสบางส่วนของคุณ


0

ตั้งแต่ปีพ. ศ. 2562 คุณสามารถมีคลาสได้เพียงบางส่วนในแอสเซมบลีที่ต่างกันโดยใช้กลวิธี เคล็ดลับนี้มีการอธิบายและแสดงให้เห็นในบทความนี้:

https://www.notion.so/vapolia/Secret-feature-Xamarin-Forms-control-s-auto-registration-1fd6f1b0d98d4aabb2defa0eb14961fa

จะใช้ที่เป็นแกนหลักของมันขยาย MSBuild.Sdk.Extras ไปยัง SDK เช่นโครงการซึ่งแก้ข้อ จำกัด ของการมีบางส่วนบางส่วนของชั้นเรียนในการชุมนุมเดียวกันโดยใช้หนึ่งโครงการที่มีเป้าหมายพร้อมกันหลายรายการได้อย่างมีประสิทธิภาพ ของโครงการเดียวกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.