C#接口列表的继承

时间:2019-03-15 11:27:12

标签: c# inheritance interface

我对C#接口有点陌生,并且遇到了继承接口列表问题的扩展方法的尴尬解决方案。示例界面如下所示:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
    <div class="row">
        <div class="col-lg-12">
            <p class="add">Addition</p>
            <table>

                <tr>
                    <td>1</td>
                    <td>+</td>
                    <td>93</td>
                    <td>=</td>
                    <td><input type="number" name="valu" class="valu1"></td>
                    <!-- the last for the glyphicon -->
                    <td></td>
                </tr>
                <tr>
                    <td>1</td>
                    <td>+</td>
                    <td>13</td>
                    <td>=</td>
                    <td><input type="number" name="valu" class="valu2"></td>
                    <td></td>
                </tr>
                <tr>
                    <td>1</td>
                    <td>+</td>
                    <td>3</td>
                    <td>=</td>
                    <td><input type="number" name="valu" class="valu3"></td>
                    <td></td>
                </tr>
                <tr>
                    <td>1</td>
                    <td>+</td>
                    <td>30</td>
                    <td>=</td>
                    <td><input type="number" name="valu" class="valu4"></td>
                    <td></td>
                </tr>
                <tr>
                </tr>
            </table>
        </div>
    </div>
  
    <table class="zahlen" style="margin:0 auto;">
        <tr>
            <td><button>0</button></td>
            <td><button>1</button></td>
            <td><button>2</button></td>
            <td><button>3</button></td>
            <td><button>4</button></td>

        </tr>
        <tr>
            <td><button>5</button></td>
            <td><button>6</button></td>
            <td><button>7</button></td>
            <td><button>8</button></td>
            <td><button>9</button></td>
        </tr>
    </table>
  <p class="error" style="color: red"></p>
</body>

使用扩展方法:

public interface IData
{
    int Value { get; set; }
}

public interface IDataWithName : IData
{
    string Name { get; set; }
}

public interface IDataContainer
{
    IList<IData> DataList { get; set; }
}

public interface IDataWithNameContainer : IDataContainer
{
    new IList<IDataWithName> DataList { get; set; }
}

实现这些接口时,需要同时实现IList DataList和IList IDataContainer.DataList。尽管这是可能的,但生成的代码并不雅致:

public static class ExtensionMethod
{
    public static int CountNumberOfIDataItems(this IDataContainer i)
    {
        return i.DataList.Count();
    }
}

每次调用扩展名时复制列表都可能导致某些性能问题,并且还需要进行额外的检查,以确保IDataContainer上的任何其他方法都不会尝试添加从IData继承但不是IDataWithName的类。

感觉应该有一种更好的方式来使用扩展方法,这种方法不易受到将来扩展问题的影响。我能想到的最好的解决方案是将IList DataList从IDataContainer中取出,并对每个包含列表的类都有单独的扩展方法。

谁能提出比这更好的解决方案?

2 个答案:

答案 0 :(得分:3)

问题在于IDataWithNameContainer隐藏了它从DataList继承的IDataContainer属性,而不是扩展方法。它不应该这样做。

创建仅接受特定IData实现的派生容器类的简单方法是使容器接口通用,并在IDataWithNameContainer中使用更严格的类型约束:

public interface IData
{
    int Value { get; set; }
}

public interface IDataWithName : IData
{
    string Name { get; set; }
}

public interface IDataContainer<T> where T:IData
{
    IList<T> DataList { get; set; }
}

public interface IDataWithNameContainer<T> : IDataContainer<T> where T:IDataWithName
{

}

public static class ExtensionMethod
{
    public static int CountNumberOfIDataItems<T>(this IDataContainer<T> i) where T:IData
    {
        return i.DataList.Count;
    }
}

以这种方式创建命名容器很容易:

public class Boo:IDataWithName 
{
    public int Value { get; set; }
    public string Name { get; set; }
}


public class BooContainer: IDataWithNameContainer<Boo>
{
    public IList<Boo> DataList { get; set; }
}

更新

没有理由顺便将新项目循环添加到DataList中。 List构造函数可以接受带有初始值的IEnumerable:

public class BooContainer: IDataWithNameContainer<Boo>
{
    IList<Boo> _list=new List<Boo>();
    public IList<Boo> DataList 
    { 
        get => _list; 
        set => _list=new List<Boo>(value); 
    }
}

这可以通过将列表和数组的内容复制到新列表中来将它们存储到DataList

如果有人设置为null,则将抛出此错误。为了避免这种情况,可以在设置器中使用null替换运算符:

    set => _list=new List<Boo>(value ?? new Boo[0]); 

答案 1 :(得分:0)

您不需要$re = [regex]'ixi:\+49.*(\d{4})' $used = Get-ADUser -Filter * -Properties ProxyAddresses | Where ProxyAddressess -match $re | Select-Object @{N='ixi';E={$Matches.Groups[1].Value}}| Select-Object -ExpandProperty ixi $UnUsed = Compare-Object ($used|sort) $all | Select-Object -Expandproperty InputObject IDataContainer。您已经在IDataWithNameContainer界面中有了值,那么为什么IDataWithName也继承自IDataWithNameContainer?这不是为什么要创建额外的界面吗?

IDataContainer

这些问题不需要答案;他们是这个答案的一部分,直言不讳的是,这只是糟糕的设计。

您已经过度设计了界面以简化其他工作(我想很好),但是无论如何您还是添加了其他工作:/

只需使您的班级像这样:

IData
IDataWithName : IData
IList<IDataWithName>  //This already has a list of (name) and (value)