【问题标题】:Is it possible to use generic constraints based on attributes rather than types? [duplicate]是否可以使用基于属性而不是类型的通用约束? [复制]
【发布时间】:2009-08-28 11:42:33
【问题描述】:

我正在尝试编写一个负责持久化应用程序选项的类。由于需要保留选项,因此我发送的值必须是可序列化的。

一开始我以为我可以用这样的签名写一个方法:

Public Sub SaveOption(Of T As ISerializable)(ByVal id As String, ByVal value As T)

或者如果你更喜欢 C#:

public void SaveOption<T>(string id, T value) where T : ISerializable  

原则上这没问题,但是具有&lt;Serializable&gt; 属性的类型呢?最值得注意的例子是 System.String,它没有实现ISerializable,但显然它是我应该能够保存的类型。

那么,有没有一种方法可以在编译时根据它们的属性限制方法中允许哪些类型?

【问题讨论】:

    标签: c# .net vb.net .net-2.0


    【解决方案1】:

    您可能对其他类型有重载 - 以您的字符串为例:

    public void SaveOption(string id, string value)
    

    但是;可序列化是……棘手的;我希望您必须在运行时检查它。

    【讨论】:

    • 我可以为一些系统类型添加重载,但我需要支持大量其他类型,但它们没有实现接口。我想我必须在运行时检查东西,这很遗憾。
    【解决方案2】:

    属性约束不会有太大的作用,因为属性通常不会在编译时提供任何保证,它们是运行时而不是编译器的信息。

    在序列化的情况下,[Serializable]属性只是一个指示你可以在运行时尝试序列化,而ISerializable保证你可以序列化它,因为你绝对可以调用@987654323 @ 并且确保它做正确的事情是班级的问题。

    例如,我可以拥有

    [Serializable]
    class GoodClass
    {
        public object Property { get; set; }
    }
    
    class BadClass
    {
    }
    

    但是GoodClass确实不比BadClass好,因为我能做到

    MemoryStream ms = new MemoryStream();
    BinaryFormatter f = new BinaryFormatter();
    
    GoodClass obj = new GoodClass();
    f.Serialize(ms, obj); // OK
    
    obj.Property = new BadClass();
    f.Serialize(ms, obj); // BOOM
    

    编辑:属性也不是继承的,因此编译器不能确定在运行时传递的对象是否仍然具有您要求的属性:

    class NotSoGoodClass : GoodClass // No [Serializable] attribute
    {
    }
    
    ...
    
    SaveOption<GoodClass>( "id", new NotSoGoodClass() ) // oops
    

    【讨论】:

      【解决方案3】:

      不。 :(

      啊,不,实际上在 C# 4.0 中他们已经引入了代码契约。这应该在这里工作。

      来自此链接的示例:CLR 4.0: Code Contracts

      public void BuyMoreStuff(Item[] cart, ref Decimal totalCost, Item i)
      {       
          CodeContract.Requires(totalCost >=0);
          CodeContract.Requires(cart != null);
          CodeContract.Requires(CodeContract.ForAll(cart, s => s != i));
      
          CodeContract.Ensures(CodeContract.Exists(cart, s => s == i);
          CodeContract.Ensures(totalCost >= CodeContract.OldValue(totalCost));
          CodeContract.EnsuresOnThrow<IOException>(totalCost == CodeContract.OldValue(totalCost));
      
          // Do some stuff
          …
      }
      

      【讨论】:

        【解决方案4】:

        可以检查这一点,但你是对的,它必须在运行时完成,但比仅仅抛出异常更正式。

        public static byte[] SerializeObject<T>(this T obj)
        {
            Contract.Requires(typeof(T).IsSerializable);
            ...
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多