首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具体类继承抽象类,抽象类继承一般抽象类

具体类继承抽象类,抽象类继承一般抽象类
EN

Stack Overflow用户
提问于 2017-02-07 19:37:48
回答 4查看 785关注 0票数 0

我是这里的一个“老派”程序员,正在努力利用继承来实现我的优势。我发现自己在重复代码,它开始发臭了。我没有坚持干,所以我试图在这里重构一点,以减少代码重复!

我正在尝试编写要在实体中使用的值对象类,这将强制执行基本不变量。我有一个通用的抽象ValueObject类,它处理等式和散列,如下所示:

代码语言:javascript
复制
public abstract class ValueObject<T> where T : ValueObject<T>
{
    protected abstract IEnumerable<object> GetEqualityCheckAttributes();

    public override bool Equals(object other)
    {
        return Equals(other as T);
    }

    public bool Equals(T other)
    {
        if (other == null)
        {
            return false;
        }
        return GetEqualityCheckAttributes().SequenceEqual(other.GetEqualityCheckAttributes());
    }

    public static bool operator == (ValueObject<T> left, ValueObject<T> right)
    {
        return Equals(left, right);
    }

    public static bool operator != (ValueObject<T> left, ValueObject<T> right)
    {
        return !(left == right);
    }

    public override int GetHashCode()
    {
        int hash = 17;
        foreach (var obj in this.GetEqualityCheckAttributes())
        {
            hash = hash * 31 + (obj == null ? 0 : obj.GetHashCode());
        }
        return hash;
    }
}

然后,我一直在创建我的值对象类,然后实现这个抽象类,并提供逻辑以确保不能在无效的状态下创建对象。这就是我开始违反DRY的时候,我用相同的代码创建了许多对象(例如,最大长度为50或30或10的所需字符串)。

因此,我希望将强制执行不变量的代码放在自己的类中,并让我的具体值对象类继承该功能。类似于(这不是编译,请参见下面):

代码语言:javascript
复制
public abstract class RequiredStringValueObject : ValueObject<string>
{
    private string _value;
    protected string _fieldName;
    protected byte _maxLength;

    public string Value
    {
        get
        {
            return _value;
        }
        protected set
        {
            if (value == null || string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentNullException(_fieldName, _fieldName + " must be supplied.");
            }
            value = value.Trim();
            if (value.Length > _maxLength)
            {
                throw new ArgumentOutOfRangeException(_fieldName, value, _fieldName + " can't be longer than " + _maxLength.ToString() + " characters.");
            }
            _value = value;
        }
    }
}

然后,我可以在具体的类中“使用”所有这些功能,如下所示:

代码语言:javascript
复制
public class FirstName : RequiredStringValueObject
{
    private FirstName(string value, string FieldName, byte MaxLength)
    {
        _fieldName = FieldName;
        _maxLength = MaxLength;
        Value = value;
    }
    public static FirstName Create(string value, string FieldName, byte MaxLength)
    {
        return new FirstName(value, FieldName, MaxLength);
    }

    protected override IEnumerable<object> GetEqualityCheckAttributes()
    {
        return new List<object> { Value };
    }
}

对我来说,所有这些似乎都是解决问题的合理方法。问题是我在RequiredStringValueObject声明中得到了一个编译器错误:

类型string不能用作泛型类型或方法ValueObject<T>中的类型参数T。不存在从stringValueObject<string>的隐式引用转换。

我不完全理解错误信息。我想做的事有可能吗?有办法让这件事成功吗?还是我可以/应该采取的另一种方法?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-02-07 19:47:26

问题来自于这一行:

代码语言:javascript
复制
abstract class ValueObject<T> where T : ValueObject<T>

您需要TValueObject<T>继承,所以当您编写:

代码语言:javascript
复制
RequiredStringValueObject : ValueObject<string>

string不从ValueObject继承(很明显),所以您需要从ValueObject<ValueObject<string>>继承,但这也违反了约束,而且很好.它的海龟一直往下走。

简单的解决方法是删除类型约束;似乎您的代码主要是为了以任何方式处理object,所以您不需要它。放置任何类型的“递归”类型约束只会导致您在此设置中出现问题。如果你真的需要这样的东西,你可能需要用构图代替,比如:

代码语言:javascript
复制
public interface IValueMethods<T>
{
   //required methods
}

//Constructor for value object
public ValueObject<T>(IValueMethods<T> commonMethods)
{
}

然后,您可以传入一组方法作为单独的对象使用。

票数 2
EN

Stack Overflow用户

发布于 2017-02-07 19:45:36

在泛型类型T上有一个where子句:

代码语言:javascript
复制
public abstract class ValueObject<T> where T : ValueObject<T>

这告诉编译器T必须从ValueObject派生,而字符串不能。

你想用那个T:子句来执行什么?你可能想省略它。

票数 4
EN

Stack Overflow用户

发布于 2017-02-07 20:08:55

同意@BradleyDotNET所说的话。可能的修复方法如下所示:

代码语言:javascript
复制
public abstract class ValueObjectBase
{
    public abstract IEnumerable<object> GetEqualityCheckAttributes();
}

public abstract class ValueObject<T> : ValueObjectBase where T : class
{
    public override bool Equals(object other)
    {
        if (other is ValueObjectBase)
            return Equals(other as ValueObjectBase);

        return Equals(other as T);
    }

    public bool Equals(T other)
    {

        if (other == null)
        {
            return false;
        }
        return other.Equals(this);

    }

    public bool Equals(ValueObjectBase other)
    {
        return GetEqualityCheckAttributes().SequenceEqual(other.GetEqualityCheckAttributes());
    }

    public static bool operator ==(ValueObject<T> left, ValueObject<T> right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(ValueObject<T> left, ValueObject<T> right)
    {
        return !(left == right);
    }

    public override int GetHashCode()
    {
        int hash = 17;
        foreach (var obj in this.GetEqualityCheckAttributes())
        {
            hash = hash * 31 + (obj == null ? 0 : obj.GetHashCode());
        }
        return hash;
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42098481

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档