C# 佩蒂); } }
编辑: 如果扩展属性/数据的数量不是那么多,另一个解决方案可能是使基础模型通用C# 佩蒂); } },c#,oop,C#,Oop,编辑: 如果扩展属性/数据的数量不是那么多,另一个解决方案可能是使基础模型通用 public class BaseClass { } public class BaseClass<T, U, V> : BaseClass { public T Extension1 { get; set; } public U Extension2 { get; set; } public V Extension3 { get; set; } } public class
public class BaseClass
{
}
public class BaseClass<T, U, V> : BaseClass
{
public T Extension1 { get; set; }
public U Extension2 { get; set; }
public V Extension3 { get; set; }
}
public class ClassThatIsUsingSpecificBaseClass
{
public void Test(BaseClass<int, int, string> baseClass)
{
//baseClass.Extension1 ...;
//baseClass.Extension2 ...;
}
}
public class ClassThatIsUsingBaseClass
{
public void Test(BaseClass baseClass)
{
}
}
公共类基类
{
}
公共类基类:基类
{
公共T扩展1{get;set;}
公共U扩展2{get;set;}
公共V扩展3{get;set;}
}
使用SpecificBaseClass的公共类
{
公共无效测试(基类基类)
{
//baseClass.Extension1。。。;
//baseClass.Extension2。。。;
}
}
使用BaseClass的公共类
{
公共无效测试(基类基类)
{
}
}
这将是类型安全的,不涉及强制转换,并且将只派生一个基类,而不是针对每个独特的客户需求/数据派生一个基类。我不确定最惯用的方式是什么,但我同意您的意见,我更喜欢使用聚合的解决方案 如果您使用一组标记接口和帮助器以特定的方式进行设置,每个接口(每个客户)最好只有一个具体的实现,那么您可以使此类型相对安全,并通过具有允许将此数据映射到例如字典的基础设施来提供一些通用访问 我创建了一个非常粗略的原型实现,只是为了说明一些想法。我将在这里发布亮点,在这里可以找到一个“完整”的例子(大约200行) 我们首先分别为可扩展类和扩展数据类提供两个标记接口,这两个接口很容易通过反射发现
// Marker interface, allowing reflection & discovery
public interface IExtendable {}
// Marker interface, allowing reflection & discovery
public interface IExtensionData {}
我们使这一类型更易于保存和修复聚合关系:
// Making it type safe
public interface IExtendableOf<T> : IExtendable where T : class, IExtendable
{
IExtensionDataFor<T> ExtensionData { get; set; }
}
// Making it type safe & discoverable through reflection.
public interface IExtensionDataFor<T> : IExtensionData where T : class
{
}
在“CustomerOne”数据扩展程序集中,您为此类定义了扩展,如下所示:
// Customer specific extension data for a phone number
public class PhoneNumberExtension : IExtensionDataFor<PhoneNumber>
{
public string Prefix { get; set; }
}
// Marker interface, allowing reflection & discovery
public interface IExtendable {}
// Marker interface, allowing reflection & discovery
public interface IExtensionData {}
// Making it type safe
public interface IExtendableOf<T> : IExtendable where T : class, IExtendable
{
IExtensionDataFor<T> ExtensionData { get; set; }
}
// Making it type safe & discoverable through reflection.
public interface IExtensionDataFor<T> : IExtensionData where T : class
{
}
// Factory implemented for each specific customer, discoverable.
public interface IExtensionProvider
{
IExtensionDataFor<TExtendable> CreateExtensionData<TExtendable>()
where TExtendable : class, IExtendableOf<TExtendable>;
IExtensionDataFor<TExtendable> CreateExtensionDataFor<TExtendable>(TExtendable instance)
where TExtendable : class, IExtendableOf<TExtendable>;
}
// Example "core" class with extension data
public class PhoneNumber : IExtendableOf<PhoneNumber>
{
public enum Kind { Internal, External }
public string AreaCode { get; set; }
public string Number { get; set; }
public Kind NumberKind { get; set; }
public virtual IExtensionDataFor<PhoneNumber> ExtensionData { get; set; }
}
// Customer specific extension data for a phone number
public class PhoneNumberExtension : IExtensionDataFor<PhoneNumber>
{
public string Prefix { get; set; }
}
// A quick & dirty example.
public static class TryExtensions
{
static TryExtensions()
{
ExtensionProvider.Use(new TryOuts.ExtensionData.CustomerOne.ExtensionProvider());
}
public static void Run()
{
var phoneNumberOne = new PhoneNumber { NumberKind = PhoneNumber.Kind.Internal, AreaCode = "(231)", Number = "567 891 123" }.Extend();
var phoneNumberTwo = new PhoneNumber { NumberKind = PhoneNumber.Kind.External, AreaCode = "(567)", Number = "555 666 777" }.Extend();
Console.WriteLine("Phone Number 1: {0}", phoneNumberOne.ExtensionData.ToDictionary()["Prefix"]);
Console.WriteLine("Phone Number 2: {0}", phoneNumberTwo.ExtensionData.ToDictionary()["Prefix"]);
CodeThatKnowsCustomerOne(phoneNumberOne);
}
public static void CodeThatKnowsCustomerOne(PhoneNumber number)
{
var extensionData = number.ExtensionData as TryOuts.ExtensionData.CustomerOne.PhoneNumberExtension;
Console.WriteLine("Prefix: {0}", extensionData.Prefix);
}
}