利用可选参数的边缘情况,通过接口滥用语言来强制实现ToString
本文关键字:语言 接口 ToString 实现 参数 边缘 情况 | 更新日期: 2023-09-27 18:12:10
我有一个接口IKey
,我想有一个方法,它将返回键作为字符串。我们考虑过这样一个方法:
String GetAsString();
将返回字符串表示形式,但希望能够在接口中再次声明ToString()
以强制实现者实现它,但它并没有强制他们这样做,因为他们继承了Object
的实现。这是建议:
public interface IKey
{
string ToString(string dummyParameter=null);
}
这强制在任何实现类中实现该方法,但由于可选参数工作的方式,调用者不需要为此提供值,并且您确保对对象上的ToString()
方法的任何调用,无论是转换为接口IKey
还是实现类将始终调用类实现而不是Object
实现。
在实现中,我们可以忽略dummyParameter
并返回我们想要的,因为知道调用ToString()
总是会实际调用ToString(null)
。
现在我觉得这是不对的,但同时它也有一些很好的东西。它几乎与GetAsString()
方法完全相同,因为它只能在IKey
接口和派生类上调用,除了它看起来像我们想要使用的更自然的ToString()
方法,并且我们能够在子类中强制实现。
已经说过,没有使用的虚拟参数感觉不对。
所以这很可怕吗?还是大?
这个问题适合SO还是应该由程序员来问?
public class Key :IKey
{
public string ToString(string abc = null)
{
return "100";
}
}
Key key = new Key ();
Trace.WriteLine (key.ToString());
Trace.WriteLine (key.ToString(null));
Trace.WriteLine (key.ToString("ac"));
Trace.WriteLine (((object)key).ToString());
输出:100
100
100
Blah.Tests.Key
听起来您正在使用应该使用抽象类的接口。下面的类明确要求后代已经实现了ToString
。
abstract class X
{
public abstract override string ToString();
}
从我的角度来看,这样的ToString()
方法在自定义接口中有点混乱,因为自定义接口暴露了一个标准的和众所周知的名称ToString()
的方法。
我更喜欢更直接和明显的东西,比如:
string KeyText { get; }
或方法
string ConvertKeyToString();
另一个答案已经建议抽象类,我认为这是最好的选择。
将带有默认参数的ToString添加到接口的想法在实际中并不太有效。当调用不带参数的ToString时,重载解析将找到不带参数的ToString(我必须说,这似乎很直观)。考虑这个程序的输出:
void Main()
{
Console.WriteLine(new Key().ToString());
}
public interface IKey
{
string ToString(string dummy = null);
}
class Key : IKey
{
public string ToString(string dummy)
{
return "myspecialKey";
}
}
输出object.ToString()实现。因此,如果您被限制使用接口,我会将方法命名为ToString()以外的其他名称。
那
(IMO) - ToString()
已经有一个非常明确的目的和意义。根据名称劫持它可能很方便,但是说它是必需的,你就重新利用了一些你不应该使用的东西。
答案是有你自己的单独的方法,最初的想法。否则意味着所有关于ToString()
的。net文档都变成了"错误的"。
。Tag属性是许多UI控件上的对象。它可能是你想要在某种控件库中"标记"控件。仅仅因为名字合适,类型合适,并不意味着意思是一样的,你可以抓住它并重新使用它。
我还建议考虑更改接口名称;除非实现者实际上是关键?我的印象是它们只是"有键",或者有一些与它们相关的键。在这种情况下,IKeyed
, IIndexed
或其他可能更好。那么string Key { get; }
就变得更有吸引力了。也许这只是名字的问题。
我认为这是滥用,因为你在这里暗示的问题:
…并且您要确保对对象的ToString()方法的任何调用,无论是转换为接口IKey还是实现类,都将始终调用类实现而不是对象实现。
考虑以下代码:
IKey someKey = ...;
string keyAsString = someKey.ToString();
object someKeyAsObject = (object)someKey;
string keyAsString2 = someKeyAsObject.ToString();
任何人看到这段代码都会认为keyAsString
和keyAsString2
是相同的。然而,这些将调用不同的方法,这些方法可能具有不同的行为。唷!
可怕,如果我只能选一个词…更准确地说,如果我在野外遇到这种情况,我的反应是困惑和怀疑。
在设计API时,我尽量遵循一条最重要的规则:不要让开发人员感到惊讶。
这肯定会是一个惊喜。它排除了使用预期的输出和使用ToString()
而不需要特别的努力。事实上,没有任何迹象表明需要特别的努力,这将是"惊喜"的一部分。ToString()
的默认实现最终比我预期的更频繁地被使用。我将避免禁止或扭曲它的使用,除非我没有其他合理的方法来解决问题。
我不认为这会比一个已经不是object
成员的命名良好的方法/属性更"自然"。
刚刚遇到这个。让接口继承iformatable怎么样?
http://msdn.microsoft.com/en-us/library/system.iformattable.aspx我自己没有这样做,所以我可能是错的,但这似乎可以为您的接口使用ToString
方法的格式参数。请注意,您仍然没有改变无参数的ToString
,我同意其他人不应该在接口中这样做,而是使用具有可识别格式输入的ToString(string format, IFormatProvider provider)
,这基本上意味着"在它实现I的上下文中给我这个对象的描述"。显然,每个实现的类都需要对方法进行编码,但这样做是恰当的。