我对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中取出,并对每个包含列表的类都有单独的扩展方法。
谁能提出比这更好的解决方案?
答案 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)