【问题标题】:Generic Interface inheriting Non-Generic One C#继承非通用 C# 的通用接口
【发布时间】:2014-02-07 19:02:08
【问题描述】:

这是课程设计问题。

我有主要的抽象类

public abstract class AbstractBlockRule
{
    public long Id{get;set;}
    public abstract List<IRestriction> Restrictions {get;};
}

public interface IRestriction{}

public interface IRestriction<T>:IRestriction where T:struct
{
    T Limit {get;} 
}

public TimeRestriction:IRestriction<TimeSpan>
{
    public TimeSpan Limit{get;set;}
}

public AgeRestriction:IRestriction<int>
{
    public int Limit{get;set;}
}

public class BlockRule:AbstractBlockRule
{
    public virtual List<IRestriction> Restrictions {get;set;}
}

BlockRule rule=new BlockRule();
TimeRestriction t=new TimeRestriction();
AgeRestriction a=new AgeRestriction();

rule.Restrictions.Add(t);
rule.Restrictions.Add(a);

我必须使用非泛型接口 IRestriction 以避免在主抽象类中指定泛型类型 T。我对泛型很陌生。谁能告诉我如何更好地设计这个东西?

【问题讨论】:

  • 对我来说很难改进你的代码。如果您愿意,非通用基本接口可以具有属性ValueType BoxedLimit {get;},但我不确定它是否有用。毕竟,你为什么需要不同类型对象的List&lt;&gt;
  • (当然,使泛型接口协变IRestriction&lt;out T&gt; 的明显想法在将它与值类型(结构)一起使用时没有用,因为 C# 和 .NET 不支持与值类型。)
  • 我不确定您为什么不将抽象类或方法设为通用。 Limit 是最小值还是最大值?如果是这样,也许IComparable 会更有用。

标签: c# .net oop generics


【解决方案1】:

您的方法是典型的(例如,IEnumerable 像这样实现 IEnumerable)。如果您想为代码的使用者提供最大的效用,最好在非泛型接口上提供一个非泛型访问器,然后将其隐藏在泛型实现中。例如:

public abstract class AbstractBlockRule
{
    public long Id{get;set;}
    public abstract List<IRestriction> Restrictions { get; set; }
}

public interface IRestriction
{
    object Limit { get; }
}

public interface IRestriction<T> : IRestriction 
    where T:struct
{
    // hide IRestriction.Limit
    new T Limit {get;} 
}

public abstract class RestrictionBase<T> : IRestriction<T>
    where T:struct
{
    // explicit implementation
    object IRestriction.Limit
    {
        get { return Limit; }
    }

    // override when required
    public virtual T Limit { get; set; }
}

public class TimeRestriction : RestrictionBase<TimeSpan>
{
}

public class AgeRestriction : RestrictionBase<TimeSpan>
{
}

public class BlockRule : AbstractBlockRule
{
    public override List<IRestriction> Restrictions { get; set; }
}

我在这里也展示了使用基本限制类​​,但这不是必需的。

【讨论】:

    【解决方案2】:

    运行时将IRestriction&lt;TimeSpan&gt;IRestriction&lt;int&gt; 视为不同的不同类(它们甚至有自己的一组静态变量)。在您的情况下,继承层次结构中 IRestriction&lt;TimeSpan&gt;IRestriction&lt;int&gt; 共有的唯一类是 IRestrictionobject

    确实,拥有IRestriction 的列表是唯一明智的选择。


    附带说明:无论您处理的是IRestriction&lt;TimeSpan&gt; 还是IRestriction&lt;int&gt;,您都可能想要访问其中的属性Limit。在这种情况下,我要做的是在IRestriction 上定义另一个属性object Limit { get; },并将其隐藏在实际实现中。像这样:

    public interface IRestriction
    {
        object Limit { get; }
    }
    
    public interface IRestriction<T> : IRestriction
        where T : struct
    {
        new T Limit { get; set; }
    }
    
    public class TimeRestriction : IRestriction<TimeSpan>
    {
        public TimeSpan Limit { get; set; }
    
        // Explicit interface member:
        // This is hidden from IntelliSense
        // unless you cast to IRestriction.
        object IRestriction.Limit
        {
            get
            {
                // Note: boxing happens here.
                return (object)Limit;
            }
        }
    }
    

    这样,当您不在乎它是什么类型时,您可以在所有IRestriction 上以object 的形式访问Limit。例如:

    foreach(IRestriction restriction in this.Restrictions)
    {
        Console.WriteLine(restriction.Limit);
    }
    

    【讨论】:

      【解决方案3】:

      接口是实现合同的实体需要遵循的合同。

      你已经创建了两个同名的合约IRestriction

      据我所知,您基本上可能需要一个可以限制类的标志,它应该实现 IRestriction 非泛型接口。

      第二个接口似乎是包含限制属性的可限制对象。 因此,第二个IRestriction 接口的定义可以是ILimitRestriction 或任何适合您业务需求的名称。

      因此ILimitRestriction 可以从IRestriction 继承,这将标记继承ILimitRestriction 的类仍然是IRestriction 的对象

      public abstract class AbstractBlockRule
      {
          public long Id{get;set;}
          public abstract List<IRestriction> Restrictions {get;};
      }
      
      public interface IRestriction{}
      
      public interface IRestrictionWithLimit<T>:IRestriction where T:struct
      {
          T Limit {get;} 
      }
      
      public TimeRestriction:IRestrictionWithLimit<TimeSpan>
      {
          public TimeSpan Limit{get;set;}
      }
      
      public AgeRestriction:IRestrictionWithLimit<int>
      {
          public int Limit{get;set;}
      }
      
      public class BlockRule:AbstractBlockRule
      {
          public virtual List<IRestriction> Restrictions {get;set;}
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-25
        • 2012-09-04
        • 2015-10-03
        • 1970-01-01
        • 2010-09-17
        • 1970-01-01
        • 2019-01-05
        相关资源
        最近更新 更多