是否利用可选参数边缘情况通过语言的接口滥用强制实现 ToString?

发布于 2024-12-11 13:17:37 字数 1442 浏览 0 评论 0原文

我有一个接口 IKey 我想要一个方法将密钥作为字符串返回。我们考虑过有一个这样的方法:

String GetAsString();

它将返回字符串表示形式,但希望能够在接口中再次声明 ToString() 以强制实现者实现它,但事实并非如此。不要强迫它们这样做,因为它们有一个继承自 Object 的实现。建议这样做:

public interface IKey
{
    string ToString(string dummyParameter=null);
}

这会强制在任何实现类中实现该方法,但由于 可选参数的工作方式 调用者不需要为此提供值,并且您确保对转换为接口 IKey 或实现类的对象上的 ToString() 方法将始终调用类实现,而不是 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

I have an interface IKey which I want to have a method which will return the key as a string. We looked at having a method like this:

String GetAsString();

which would return the string representation, but would have liked to be able to declare ToString() again in the interface to force implementers to implement it, but it doesn't force them to as they have an implementation inherited from Object. This was suggested:

public interface IKey
{
    string ToString(string dummyParameter=null);
}

this forces an implementation of the method in any implementing class, but due to the way that optional parameters work callers do not need to provide a value for this, and you ensure that any calls to the ToString() method on objects which are either cast as the interface IKey or the implementing class will always call the class implementation and not the Object implementation.

In the implementations we can just ignore the dummyParameter and return what we want, safe in the knowledge that calling ToString() will always actually call ToString(null).

Now this feels wrong all over to me, but at the same time it does have something quite nice about it. It is almost exactly the same as having a method GetAsString() as this could only be called on the IKey interface and derived classes except that it looks like the more natural ToString() method that we want to use and that we are able to force the implementing of in the child class.

Having said that the dummy parameter which is not used feels wrong.

So is this horrendous? Or great?

And is this question appropriate for SO or should it be on Programmers?

Examples

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());

output:

100
100
100
Blah.Tests.Key

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

留蓝 2024-12-18 13:17:37

听起来您正在使用一个应该使用抽象类的接口。下面的类明确要求后代实现 ToString

abstract class X
{
    public abstract override string ToString();
}

It sounds like you're using an interface where you should be using an abstract class. The class below explicitly requires descendants to have implemented ToString.

abstract class X
{
    public abstract override string ToString();
}
从来不烧饼 2024-12-18 13:17:37

从我的角度来看,自定义接口中的此类 ToString() 方法稍微搞乱了事情,因为自定义接口公开了一个具有标准且众所周知的名称 ToString() 的方法。

我更喜欢更直接和明显的方法,例如:

string KeyText { get; }

OR 方法

string ConvertKeyToString();

From my point of view such ToString() method in a custom interface slightly messed up things because a custom interface exposed a method with standard and well known name ToString().

I prefer something more straightforward and obvious like:

string KeyText { get; }

OR method

string ConvertKeyToString();
葬花如无物 2024-12-18 13:17:37

另一个答案已经建议使用抽象类,我认为这是最好的选择。

在接口中添加带有默认参数的 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() 之外的其他名称。

Another answer already suggests the abstract class, which I think is the best option for this.

The idea of adding a ToString with a default parameter to the interface doesn't work too well in practive. The overload resolution will find the ToString without parameters when called without parameters (which, I must say, seems intuitive). Consider the output of this program:

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";
    }
}

This outputs the object.ToString() implementation. Therefore, if you are restricted to use an interface, I would name the method something else than ToString().

宛菡 2024-12-18 13:17:37

重新利用

(IMO) -ToString() 已经有了非常明确的目的和含义。根据名称劫持它可能对您来说很方便,但是通过说这是必需的,您正在重新利用一些不应该使用的东西。

答案是有自己独立的方法,最初的想法。任何其他内容都意味着所有有关 ToString() 的 .NET 文档都将变得“错误”。

例如,Tag 属性是许多 UI 控件上的一个对象。您可能想在某种控件库中“标记”控件。仅仅因为名称合适、类型合适,并不意味着含义相同,您可以抓住它并重新利用它。

命名

我还建议考虑更改您的界面名称;除非实施者实际上是关键?我的印象是它们只是“有钥匙”,或者有一些与之相关的钥匙。在这种情况下,IKeyedIIndexed 或其他东西可能会更好。然后是一个string Key { get; } 变得更具吸引力。也许这只是命名问题。?

Re-purposing

(IMO) -ToString() already has a very well-defined purpose and meaning. It may be convenient for you to hijack it based on the name, but by saying it's required you're re-purposing something that you shouldn't.

The answer is to have your own separate method, the initial idea. Anything else means all the .NET documentation about ToString() becomes 'wrong'.

E.g. the Tag property being an object on many UI controls. It could be that you want to 'tag' controls in some kind of control gallery. Just because the name fits, and the type fits, doesn't mean the meaning is the same and you can grab hold of it and re-purpose it.

Naming

I would also suggest considering changing your interface name; unless the implementers are actually keys? I get the impression that they are simply 'keyed', or have some key associated with them. In which case, IKeyed, IIndexed or something might be better. Then a string Key { get; } becomes more attractive. Perhaps it's just the naming that's the issue here.?

ま昔日黯然 2024-12-18 13:17:37

我会称之为滥用,因为你在这里暗示的问题:

...并且您确保对转换为接口 IKey 或实现类的对象上的 ToString() 方法的任何调用将始终调用类实现而不是对象实现。

考虑以下代码:

IKey someKey = ...;
string keyAsString = someKey.ToString();
object someKeyAsObject = (object)someKey;
string keyAsString2 = someKeyAsObject.ToString();

任何查看此代码的人都会假设 keyAsStringkeyAsString2 是相同的。但是,这些将调用可能具有不同行为的不同方法。哎呀!

I would call this abuse, because of the problem you hint at right here:

...and you ensure that any calls to the ToString() method on objects which are either cast as the interface IKey or the implementing class will always call the class implementation and not the Object implementation.

Consider the following code:

IKey someKey = ...;
string keyAsString = someKey.ToString();
object someKeyAsObject = (object)someKey;
string keyAsString2 = someKeyAsObject.ToString();

Anybody looking at this code would assume that keyAsString and keyAsString2 are the same. However, these would be calling different methods that may have different behavior. Eek!

哥,最终变帅啦 2024-12-18 13:17:37

太可怕了,如果我必须选一个词的话……如果我在野外遇到这种情况,困惑和怀疑会更准确地描述我的反应。

在设计 API 时,我尝试遵循一条最重要的规则:不要让开发人员感到惊讶。

这肯定会让人感到惊讶。它排除了使用预期输出和使用ToString()而无需特殊努力。事实上,没有迹象表明需要特殊的努力,这将是一个“惊喜”。 ToString() 的默认实现最终的使用频率比我预期的要高。除非我没有其他合理的方法来解决问题,否则我会避免禁止或扭曲其使用。

我认为这不会比尚未成为 object 成员的命名良好的方法/属性“更自然”。

Horrendous, if I have to pick just one word... Confused and suspicious would more accurately describe my reaction if I came across this in the wild.

I try to follow one rule above all others when designing API's: Do not surprise the developer.

This would most certainly be a surprise. It precludes the use of the expected output and usage of ToString() without special effort. The fact that there's no indication of the special effort required would be the "surprise" bit. The default implementation of ToString() ends up getting used more often than I would have expected. I would avoid prohibiting or distorting its usage unless I had no other reasonable way to solve an issue.

I don't think this would be "more natural" than a well named method/property that isn't already a member of object.

剪不断理还乱 2024-12-18 13:17:37

刚刚遇到这个。让接口继承IFormattable怎么样?

http://msdn.microsoft.com/en-us/library/system .iformattable.aspx

我自己没有这样做过,所以我可能是错的,但这似乎可以为您的界面的 ToString 方法使用格式参数。请注意,您仍然没有更改无参数 ToString,我同意其他人不应该在界面中完成此操作,而是使用 ToString(string format, IFormatProviderprovider) 使用可识别的格式输入,基本上意味着“在该对象实现 IWhatever 的上下文中给我一个描述”。显然,每个实现的类都需要对方法进行编码,但这是正确的。

Just came across this. What about having the interface inherit IFormattable?

http://msdn.microsoft.com/en-us/library/system.iformattable.aspx

I haven't done this myself so I might be wrong, but that seems to enable use of a format parameter for a ToString method for your interface. Note you are still not alterring the parameterless ToString, which I agree with others should not be done in an interface, but instead you make use of ToString(string format, IFormatProvider provider) with a recognizable format input that basically means "give me a description of this object in the context that it implements IWhatever". Obviously each implemented classes will need to code the method, but that is only proper.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文