Q1为什么.NET中的新类仅部分实现接口?
Q2我应该在我的代码中做同样的事情吗?
我在这里问了这个问题,所以我想,好吧很久以前,你可以有不同的用法等等,现在这种实现只是出于一致性的原因而受到支持.但新课程也是如此.
旧
int[] list = new int[] {};
IList iList = (IList)list;
ilist.Add(1); //exception here
Run Code Online (Sandbox Code Playgroud)
新
ICollection c = new ConcurrentQueue<int>();
var root = c.SyncRoot; //exception here
Run Code Online (Sandbox Code Playgroud)
UPDATE
我不担心为什么我得到例外,很明显.但我不明白为什么类实现明确定义的合同,而不是所有成员(这可能导致令人不快的运行时异常)?
这个问题在某种程度上是对相关帖子的说明,我相信下面的例子描述了问题的本质.
class Program
{
public static IList<string> GetData(string arg)
{
return new string[] {"a", "b", "c"};
}
static void Main(string[] args)
{
var arg1 = "abc";
var res1 = GetData(arg1);
Console.WriteLine(res1.Count());
dynamic arg2 = "abc";
var res2 = GetData(arg2);
try
{
Console.WriteLine(res2.Count());
}
catch (RuntimeBinderException)
{
Console.WriteLine("Exception when accessing Count method");
}
IEnumerable<string> res3 = res2;
Console.WriteLine(res3.Count());
}
}
Run Code Online (Sandbox Code Playgroud)
第二次调用GetData引发异常只是因为GetData接收到一个转换为动态的参数,这不是很糟糕吗?这个方法本身很好用这个参数:它将它视为一个字符串并返回正确的结果.但结果再次被转换为动态,突然结果数据无法根据其基础类型进行处理.除非它明确地转换回静态类型,正如我们在示例的最后几行中看到的那样.
我不明白为什么必须以这种方式实施.它打破了静态和动态类型之间的互操作性.一旦使用了动态,它会感染调用链的其余部分,从而可能导致像这样的问题.
更新.有些人指出Count()是一种扩展方法,有意义的是它不被识别.然后我将res2.Count()调用更改为res2.Count(从扩展方法更改为Ilist的属性),但程序在同一个地方引发了相同的异常!现在这很奇怪.
UPDATE2.flq指出了Eric Lippert关于这个主题的博客文章,我相信这篇文章给出了为什么以这种方式实现的充分理由:http: //blogs.msdn.com/b/ericlippert/archive/2012/10/22/a -method基团的-one.aspx
.net不允许在基类中实现部分接口.作为缓解措施,我已经提出了3种替代解决方案.请帮我决定哪些在重构,编译/运行时错误,可读性方面更具普遍性.但首先是几条评论.
我的比较:
public interface IFoo
{
void Method1();
void Method2();
}
Run Code Online (Sandbox Code Playgroud)
public abstract class BaseClass1 : IFoo
{
void IFoo.Method1()
{
//some implementation
}
void IFoo.Method2()
{
IFooMethod2();
}
protected abstract void IFooMethod2();
}
public class MyClass1 : BaseClass1
{
[Obsolete("Prohibited direct call from child classes. only inteface implementation")]
protected override void IFooMethod2()
{
//some implementation
}
}
Run Code Online (Sandbox Code Playgroud)
public abstract class BaseClass2 : IFoo
{
void …Run Code Online (Sandbox Code Playgroud) 将数组转换为BindingList最简单快捷的方法是什么?
例如,如果我有这个方法:
IEnumerable<int> GetRandomNumbers()
{
// {Codes that generate numbers as List<int>}
if(generationFails == true)
{
return Enumberable.Empty<int>(); // I do this to signal that we have an error
}
return numbers;
}
Run Code Online (Sandbox Code Playgroud)
在调用方法中我做:
IEnumerable<int> AddNumber(int number)
{
var random = GetRandomNumbers();
var randomList = random as IList<int> ?? random.ToList(); // Run ToList only if needed
randomList.Add(number);
return randomList;
}
Run Code Online (Sandbox Code Playgroud)
当生成失败时,我得到一个异常"[NotSupportedException:Collection是固定大小的.]".
这是因为Enumerable empty是一个IList,因此.ToList()没有运行,然后我尝试添加到一个固定的Enumberable.Empty.我错误地认为这是一个糟糕的设计,一个继承IList的对象(其中定义了Add)应该支持Add?
我被迫做var randomList = random.ToList()或停止使用Enumberable.Empty?有更好的方法吗?
更新: 我想在我的例子中我不清楚.我希望吞下(或记录)错误,但允许操作继续而不会崩溃.我的评论"我这样做是为了表明我们有错误"是为了告诉其他开发人员阅读代码,这是一种异常行为.
蒂姆所关联的问题的答案就是我所得到的.似乎我们只是没有用于常量集合的接口,因此IList被使用.
在stackoverflow的另一个问题中,有人建议为数组编写扩展方法,但this IList<T>在扩展方法中使用了接口.我评论它应该是一个阵列,但他拒绝了.我测试了它,当然,他是对的...... :)
扩展方法:
public static void Fill<T>(this IList<T> array, T value)
{
for(var i = 0; i < array.Count; i++)
{
array[i] = value;
}
}
Run Code Online (Sandbox Code Playgroud)
测试代码:
[Test]
public void Stackoverflow()
{
int[] arr = new int[] { 1,2,3,4};
arr.Fill(2);
Assert.AreEqual(2, arr[0]);
Assert.AreEqual(2, arr[1]);
Assert.AreEqual(2, arr[2]);
Assert.AreEqual(2, arr[3]);
}
Run Code Online (Sandbox Code Playgroud)
一个array不是IList<T>.为什么这甚至编译?通过?!
我的C#类中有以下方法.
对于名为'collections'的参数,我希望能够灵活地传递List或string []数组.我知道我可以简单地将参数类型设置为对象类型,但是还有其他更高效的类型可以用来做这个吗?
public string ProcessDoc(List<string> collections, string userName)
{
//code goes here
string result = null;
...
...
return result;
}
Run Code Online (Sandbox Code Playgroud) c# ×7
collections ×2
interface ×2
.net ×1
bindinglist ×1
c#-4.0 ×1
dynamic ×1
refactoring ×1
static ×1