c# – “显式接口实现的约束……”

我无法弄清楚为什么以下不会工作,任何想法?
    公共接口IFieldSimpleItem
    {}

public interface IFieldNormalItem : IFieldSimpleItem
{ }

public class Person
{
    public virtual T Create<T>()
        where T : IFieldSimpleItem
    {
        return default(T);
    }
}

public class Bose : Person
{
    public override T Create<T>()
        where T : IFieldNormalItem //This is where the error is
    {
        return default(T);
    } 
}

我这样做的原因是,如果开发人员继承自Bose,Bose依赖于创建至少为IFieldNormalItem的实例.以下仅依赖于IFieldSimpleItem,但上述内容应强制它至少为IFieldNormalItem.

public class Person
{
    public virtual IFieldSimpleItem Create() 
    {
        return null;
    }
}

public class Bose : Person
{
    public override IFieldSimpleItem Create()  
    {
        return null;
    } 
}

干杯
安东尼

最佳答案
我很确定你使用编译器和泛型来节省一些运行时检查是不走运的.您不能覆盖尚不存在的内容,并且您不能对相同的方法使用不同的返回类型.

我不能说我完全理解你的动机,但它有技术价值.

我的第一次尝试是使用具有非虚拟公共接口的基类,然后使用另一个受保护的虚拟方法CheckCreatedType,它允许链中的任何东西在调用基类Create之前检查类型.

public class A
{
    public IFieldSimpleItem Create()
    {
        IFieldSimpleItem created = InternalCreate();
        CheckCreatedType(created);
        return created;
    }

    protected virtual IFieldSimpleItem InternalCreate()
    {
        return new SimpleImpl();
    }
    protected virtual void CheckCreatedType(IFieldSimpleItem item)
    { 
        // base class doesn't care. compiler guarantees IFieldSimpleItem
    }
}
public class B : A
{
    protected override IFieldSimpleItem InternalCreate()
    {
        // does not call base class.
        return new NormalImpl();
    }
    protected override void CheckCreatedType(IFieldSimpleItem item)
    {
        base.CheckCreatedType(item);
        if (!(item is IFieldNormalItem))
            throw new Exception("I need a normal item.");

    }
}

以下内容在运行时检查基类.无法解决的问题是你仍然需要依赖被调用的基类方法.行为不端的子类可以通过不调用base.CheckCreatedType(item)来中断所有检查.

替代方法是硬编码基类内所有子类的所有检查(坏),或以其他方式外部化检查.

尝试2 :(子)类注册他们需要的检查.

public class A
{
    public IFieldSimpleItem Create()
    {
        IFieldSimpleItem created = InternalCreate();
        CheckCreatedType(created);
        return created;
    }

    protected virtual IFieldSimpleItem InternalCreate()
    {
        return new SimpleImpl();
    }

    private void CheckCreatedType(IFieldSimpleItem item)
    {
        Type inspect = this.GetType();
        bool keepgoing = true;
        while (keepgoing)
        {
            string name = inspect.FullName;
            if (CheckDelegateMethods.ContainsKey(name))
            {
                var checkDelegate = CheckDelegateMethods[name];
                if (!checkDelegate(item))
                    throw new Exception("failed check");
            }
            if (inspect == typeof(A))
            {
                keepgoing = false;
            }
            else
            {
                inspect = inspect.BaseType;
            }
        }
    }

    private static Dictionary<string,Func<IFieldSimpleItem,bool>> CheckDelegateMethods = new Dictionary<string,Func<IFieldSimpleItem,bool>>();
    protected static void RegisterCheckOnType(string name, Func<IFieldSimpleItem,bool> checkMethod )
    {
        CheckDelegateMethods.Add(name, checkMethod);
    }
}
public class B : A
{
    static B()
    {
        RegisterCheckOnType(typeof(B).FullName, o => o is IFieldNormalItem);
    }

    protected override IFieldSimpleItem InternalCreate()
    {
        // does not call base class.
        return new NormalImpl();
    }
}

检查由子类注册一个委托在基类中调用,但没有基类知道所有规则.另请注意,它仍然是非虚拟公共接口,它允许基类在返回结果之前检查结果.

我假设你正试图抓住这是一个开发人员错误.如果它适用,您可以使用System.Diagnostics.Conditional(“DEBUG”)]装饰运行时检查方法,允许Release版本跳过检查.

我对泛型的了解并不完美,所以也许这是不必要的.但是,这里的检查不一定是单独的类型:这可以适用于其他用途.例如在Register ..中传递的委托不必只检查引用是否为特定类型’

*请注意,如上所述,在类型名称上创建字典可能不太好;这个工作有点简单,以说明使用的机制.

转载注明原文:c# – “显式接口实现的约束……” - 代码日志