【问题标题】:.Net generics -- implementation inheritance from interface.Net 泛型——从接口实现继承
【发布时间】:2013-02-28 21:51:05
【问题描述】:

我有两个对象序列“A”和“B”。比较序列应产生第三个元素序列“C”,指示是否:

  • 对象已从“A”或
  • 中“删除”
  • 从“B”“插入”。

所有剩余的元素都被认为是“匹配的”。

我想做的事:

声明Inserted<T>Deleted<T>Matched<T> 泛型类,它们从T 基类继承其所有属性。泛型类必须能够从它继承的对象实例化自己。

代码:

public interface IInstantiable<T>
{
    void CopyFrom(T o);
}

[Serializable]
public class Inserted<T> : T
    where T : IInstantiable<T>
{
    public Inserted() { }
    public Inserted(T t)
    {
        this.CopyFrom(t);
    }
}

错误:

'MyNamespace.Inserted<T>' does not contain a definition for 'CopyFrom' and no 
extension method 'CopyFrom' accepting a first argument of type 'MyNamespace.Inserted<T>' 
could be found (are you missing a using directive or an assembly reference?)

进一步讨论:

我定义了自己的IInstantiable 接口来强制CopyFrom 方法的存在。我不能使用标准的ICloneable 接口,因为它只定义了一个将对象复制到新实例的方法,而我需要对象在构造函数中复制其成员。

如果泛型定义了自己的CopyFrom 方法实现,错误就会消失;但是,这并没有达到将CopyFrom 方法专门用于处理基类的特定需求的预期目标。只有基类可以知道应该复制哪些属性。 (或者我错过了什么?)

注意:最终对象应该具有与其基类相同的公共成员,因为该对象应该能够序列化。

这在 .NET 中可行吗?

答案:

我试图做的事情是不可能的,仅仅是因为泛型类不能是模板基类的扩展。 Visual Studio 抱怨“不能从 'T' 派生,因为它是一个类型参数。” (我还没有注意到这个错误,因为我还没有在泛型类中实现CopyFrom 方法。)

如果我要将接口更改为一个类并在该类中提供一个存根实现,我可以按照下面的建议从它继承;但是,这会在我的继承层次结构中引入一个新的基类。

public class IInstantiable<T>
{
    public virtual void CopyFrom(T o) { }
}

[Serializable]
public class Inserted<T> : IInstantiable<T>
    where T : IInstantiable<T>
{
    public Inserted() { }
    public Inserted(T t)
    {
        base.CopyFrom(t);
    }
}

不幸的是,我不能以模板化形式使用这个新的基类,因为我必须在继承层次结构的根部引入它。仅当我删除模板并使其尽可能通用时才有效。

public class IInstantiable
{
    public virtual void CopyFrom(Object o) { }
}

但是,这仍然不能使我的Inserted&lt;T&gt; 泛型看起来像它初始化的对象,并且由于我不能从与类型参数相同的类型继承,所以它不适合我的初始目的。

从基于类型系统的“花哨的泛型”转向更多(咳咳)泛型注释结构可能被证明是最好的解决方案;但是,我选择的序列化方法 (XmlSerialization) 的默认行为不具有使此配置成为可行解决方案的自动支持。泛型将不起作用;改用硬编码的类定义。

【问题讨论】:

  • 首先Inserted&lt;T&gt; : T是不允许的。
  • 看起来你只是想要:public class Inserted&lt;T&gt; : IInstantiable&lt;T&gt;。这不适合你吗?
  • 好吧,我确实注意到您没有从IInstantiable&lt;T&gt; 继承,您只是基于它创建了一个模板化类型。你试过public class Inserted&lt;T&gt; : IInstantiable&lt;T&gt; : where T IInstantiable&lt;T&gt;吗? (实际上,由于您没有模板化 where 不会编译,所以不要这样做)

标签: c# generics inheritance interface


【解决方案1】:

这就是您试图在上面的代码中间接声明的内容。

[Serializable]
public class Inserted<T> : IInstantiable<T>
    where T : IInstantiable<T>
{
    public Inserted() { }
    public Inserted(T t)
    {
        this.CopyFrom(t);
    }
}

这有意义吗?

.NET 不允许您从泛型参数继承。怎么可能?泛型是在运行时评估的,但它需要在编译时知道你的类是什么类型。

【讨论】:

  • 根本不需要通用约束。
  • 绝对不可能从泛型参数继承。但我不认为这是一些根本问题。为什么编译器需要在编译时知道“the”类型?在任何情况下它都不适用于泛型。它甚至不知道内存布局(例如,值类型的参数;比如说一个长和字节的元组)。 C# 恰好不支持它。
  • 不幸的是,这个答案并没有为我想要完成的事情提供解决方案。请参阅上面的答案部分。 @Eamon,C# 恰好不支持很多东西。
【解决方案2】:

如果我理解正确,您想用对象的状态(插入、删除或匹配)的概念来注释一系列对象。

你真的不需要花哨的泛型;怎么了:

enum ChangeState { Inserted, Deleted, Matched }
struct<T> Annotated { 
    public T Obj; 
    public ChangeState;
}

您可以根据需要将其标记为序列化(Annotated 对象可以在没有相同属性/字段的情况下很好地序列化)。

虽然您可以在类型系统中编码更多信息,但我不清楚这里有什么好处。你确定要这样做吗?

【讨论】:

  • 这是一个有趣的解决方案。它确实使事情变得有些复杂,因为我将使用 XmlSerialization 创建取决于标志状态的新标记元素。元素内容需要与原始对象相同,尽管我可能可以解决这个问题。
  • 啊,这有帮助:我很难达到你的基本目标:-)。您可以使用IXmlSerializable 来确保序列化是“附加的”;即生成与它包含的对象相同的xml,只是带有一些额外的属性。
  • 是的,XmlArrayItem 属性允许我根据对象类型轻松更改元素名称。我没有看到基于对象属性值做同样事情的简单方法。到目前为止,我已经能够避免IXmlSerializable 的自定义实现——我希望保持这种方式。谢谢!
  • 是的,从外观上看,IXmlSerializable 不会真正起作用 - 它可以控制它被序列化为的元素的 内容,但不能控制名称.
猜你喜欢
  • 2012-04-11
  • 1970-01-01
  • 2020-03-02
  • 1970-01-01
  • 2014-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
相关资源
最近更新 更多