简体   繁体   English

C# 中的设计问题:Generics 或多态性或两者兼而有之?

[英]Design issue in C#: Generics or polymorphism or both?

I need some help with a design issue I'm having.我需要一些帮助来解决我遇到的设计问题。 What I try to achieve is this:我试图实现的是:

I have a main class called Document.我有一个名为 Document 的主要 class。 This Class has a list of Attribute classes.这个 Class 有一个属性类列表。 These Attribute classes have some common properties such as Identity and Name, but they differ in one property I call Value.这些 Attribute 类有一些共同的属性,例如 Identity 和 Name,但它们的不同之处在于我称之为 Value 的一个属性。 The Value type is different for each different Attribute class and be of type string, integer, List, DateTime, float, List and also classes that consists of several properties.每个不同的属性 class 的值类型是不同的,并且类型为字符串、integer、List、DateTime、float、List 以及由多个属性组成的类。 One example would be a class I would call PairAttribute that have 2 properties: Title and Description.一个例子是 class,我会调用 PairAttribute,它有 2 个属性:标题和描述。

What I try to achieve is type safety for Value property of the Attribute child classes and that these child classes should be able to be added to the Attribute list in the Document class.我试图实现的是 Attribute 子类的 Value 属性的类型安全,并且这些子类应该能够添加到 Document class 中的 Attribute 列表中。 I could have made only one Attribute class that have a Value property of type object and be done with it, but that is exactly what I try to avoid here.我本可以只制作一个属性 class ,它的 Value 属性类型为 object 并完成它,但这正是我在这里试图避免的。

The common properties (Identity and Name) should be placed in a base class I guess, lets call that AttributeBase class.我猜公共属性(身份和名称)应该放在基础 class 中,我们称之为 AttributeBase class。 But I want to have a child class, say StringAttribute, where the Value property is of type string, a IntegerAttribute class where the Value property is of type Integer, a StringListAttribute where the Value property is of type List, a PairAttribute class where the Value is a class with several properties, etc But I want to have a child class, say StringAttribute, where the Value property is of type string, a IntegerAttribute class where the Value property is of type Integer, a StringListAttribute where the Value property is of type List, a PairAttribute class where the Value是一个 class 具有多个属性等

Do you know how I can implement this?你知道我该如何实现吗? Is this a solution I should go for at all or is it a better ways of solving this type safety issue?这是我应该 go 的解决方案,还是解决此类安全问题的更好方法? I would appreciate code examples for clarification:)我将不胜感激代码示例以进行澄清:)

You don't specify a language, but the feature described by the term "generics" (as used by Java and C#) is often called " parametric polymorphism " in other languages (like ML and Haskell).您无需指定语言,但术语“泛型”(如 Java 和 C# 所使用)所描述的特性在其他语言(如 ML 和 Haskell)中通常称为“参数多态性”。 Conversely, the common meaning of " polymorphism " in Java and C# is actually more precisely called " subtype polymorphism ".反之,Java和C#中“ 多态性”的常见含义,其实更准确地称为“亚型多态性”。

The point is, whether you are using subtype polymorphism or parametric polymorphism, either way your problem calls for polymorphism, so I think you're on the right track.关键是,无论您使用的是子类型多态性还是参数多态性,无论哪种方式,您的问题都需要多态性,所以我认为您走在正确的轨道上。

The question really boils down to: when is parametric polymorphism better than subtype polymorphism?这个问题真正归结为:参数多态性何时比子类型多态性更好? The answer is actually quite simple: when it requires you to write less code.答案其实很简单:当它要求你编写更少的代码时。

So, I'd suggest you prototype both approaches, and then see which one leads to simpler, easier to understand code.所以,我建议你对这两种方法都进行原型设计,然后看看哪一种会导致更简单、更容易理解的代码。 Then do it that way.然后就这样做。

You may pass with a generic Attribute instead of inheritance/method polymorphism, but you will need to store them in some list and for that you will need an interface, because datastores in.Net cannot be a collections of undefined generic types, and if you would define them you would not be able to mix types inside:您可以使用泛型属性而不是继承/方法多态性传递,但您需要将它们存储在某个列表中,为此您需要一个接口,因为.Net 中的数据存储不能是未定义泛型类型的 collections,如果您将定义它们,您将无法在其中混合类型:

    public interface IAttribute {
        string Identity { get; set; }
        string Name { get; set; }
        T GetValue<T>();
    }

    public class Attribute<T> : IAttribute
    {

        public string Identity { get; set; }
        public string Name { get; set; }
        public T Value { get; set; }
        public Tret GetValue<Tret>() {
            return (Tret)(Object)Value;
        }
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            List<IAttribute> lst = new List<IAttribute>();
            Attribute<string> attr1 = new Attribute<string>();
            attr1.Value = "test";

            Attribute<int> attr2 = new Attribute<int>();
            attr2.Value = 2;

            lst.Add(attr1);
            lst.Add(attr2);

            string attr1val = lst[0].GetValue<string>();
            int attr2val = lst[1].GetValue<int>();

        }
    }

The (Tret)(Object) actually does not change type, it only boxes T and the (Tret) unboxes the value without using middle variables. (Tret)(Object) 实际上并没有改变类型,它只是将 T 和 (Tret) 拆箱而不使用中间变量。 This will of course fail if you miss the right type when calling GetValue<type>() .如果您在调用GetValue<type>()时错过了正确的类型,这当然会失败。 Even if compatible types are sent like Value is integer and you do GetValue<double>() -> because unboxing an integer into a double is not allowed.即使发送兼容类型,例如 Value is integer 并且您执行GetValue<double>() -> 因为将 integer 拆箱成双精度是不允许的。

Boxing/Unboxing is not as fast as casting but it ensures type safety is preserved, and there is at my knowledge no way to use generics with an compile time known interface in some other way.装箱/拆箱不如强制转换快,但它确保保留类型安全,并且据我所知,无法以其他方式将 generics 与编译时已知接口一起使用。

So this should be type safe... and without a lot of code.所以这应该是类型安全的......并且没有很多代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM