c#从派生为参数的泛型类派生

时间:2018-08-19 03:28:30

标签: c# c#-7.0

我将项目移到使用不可变的类,发现自己做了很多事情:

sealed public class ImmutableClass : IEquatable<ImmutableClass> {
    public ImmutableType1 ImmutableType1 { { get; private set; } }
    public ImmutableType2 ImmutableType2 { { get; private set; } }

    private ImmutableClass(ImmutableType1 immutableType1, immutableType2 ImmutableType2) {
      this.ImmutableType1 = immutableType1;
      this.ImmutableType2 = immutableType2;
    }

    public ImmutableClass() {
      this.ImmutableType1 = new ImmutableType1();
      this.ImmutableType2 = new ImmutableType2();
    }

    public ImmutableClass Set(ImmutableType1 immutableType1) => new ImmutableClass(immutableType1, ImmutableType2);
    public ImmutableClass Set(ImmutableType2 immutableType2) => new ImmutableClass(ImmutableType1, immutableType2);

    public override int GetHashCode() => HashCode.Combine(ImmutableType1, ImmutableType2);

    public override bool Equals(object obj) { 
      var o = obj as ImmutableClass; if (o is null) return false;
      return ImmutableType1.Equals(o.ImmutableType1) && ImmutableType2.Equals(o.ImmutableType2);

    public bool Equals(ImmutableClass o) => object.Equals(this, o); 
    public static bool operator ==(ImmutableClass o1, ImmutableClass o2) => object.Equals(o1, o2); 
    public static bool operator !=(ImmutableClass o1, ImmutableClass o2) => !object.Equals(o1, o2);
}

(我在这里强制执行约定,所有字段都是不可变的,所有字段都有一个空的ctor,并且所有字段的类型都不同,Set才能正常工作)

这很冗长,我做了很多,所以我将其概括如下:

// Implementing the IImutable empty interface denotes the class is immutable, this is then
// used in type constraints in ImmutableBase to ensure members are immutable

public interface IImmutable { };

// Abstract class to facilitate creating immutable classes

public abstract class ImmutableBase<TDerived, T1, T2> : IEquatable<TDerived>, IImmutable
  where TDerived : ImmutableBase<TDerived, T1, T2>, new()
  where T1 : IImmutable, new()
  where T2 : IImmutable, new() {

  protected ImmutableBase() { this.item1 = new T1(); this.item2 = new T2(); }

  protected T1 item1 { get; private set; }
  protected T2 item2 { get; private set; }

  public TDerived Set(T1 oitem1) => new TDerived { item1 = oitem1, item2 = item2 };
  public TDerived Set(T2 oitem2) => new TDerived { item1 = item1, item2 = oitem2 };

  public override int GetHashCode() => HashCode.Combine(item1, item2);

  public override bool Equals(object obj) {
    var o = obj as TDerived;
    return o.IsNull() ? false : item1.Equals(o.item1) && item2.Equals(o.item2);
  }

  public bool Equals(TDerived o) => object.Equals(this, o);
}

(我再次执行上述约定,并引入了一个不可变接口,所有不可变成员都必须继承该接口,并在约束中使用该接口,而且我使用了一种转换,其中继承ImmutableBase的类没有任何字段)< / p>

(然后,我为不同数量的参量(从ImmutableBaseImmutableBase<TDerived, T1>等创建了ImmutableBase<TDerived, T1, T2, T3, T4, T5, T6, T7>的更多版本)

我现在可以做:

  #pragma warning disable CS0660, CS0661

  sealed public class ImmutableClass : 
      ImmutableBase<ImmutableClass, ImmutableType1, ImmutableType2> {

    public ImmutableClass() { }

    public ImmutableType1 ImmutableType1 { get { return item1; } }
    public ImmutableType2 ImmutableType2 { get { return item2; } }

    public static bool operator ==(ImmutableClass o1, ImmutableClass o2) => object.Equals(o1, o2); 
    public static bool operator !=(ImmutableClass o1, ImmutableClass o2) => !object.Equals(o1, o2);
  }

然后:

ImmutableClass c = new ImmutableClass().Set(new ImmutableType1(1));
ImmutableClass c2 = c.Set(new ImmutableType2("hello"));
var immutableType2 = c2.ImmutableType2;

(需要使用编译指示,因为正确继承了GetHashCode和Equals(object))

但这一切都很好:

问题#1-这种继承如何起作用?我从具有Derived作为参数的泛型类继承,编译器如何解释这一点?这个定义不是递归的吗?

问题#2-如果ImmutableBase的用户添加字段,这将全部中断,是否可以编写一种可以在运行时确定类本身没有任何字段的属性?

问题#3-并不是一个真正的问题,但是总体上对此想法有何看法?

0 个答案:

没有答案
相关问题