草庐IT

C# 泛型接口(interface)特化

coder 2024-05-21 原文

我想知道是否有可能以某种方式在 C# 中专门化通用接口(interface)方法?我发现了类似的问题,但没有完全像这样的问题。现在我怀疑答案是“不,你不能”,但我想确认一下。

我有类似下面的内容。

public interface IStorage
{
    void Store<T>(T data);
}

public class Storage : IStorage
{
    public void Store<T>(T data)
    {
        Console.WriteLine("Generic");
    }

    public void Store(int data)
    {
        Console.WriteLine("Specific");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IStorage i = new Storage();
        i.Store("somestring"); // Prints Generic
        i.Store(1); // Prints Generic
        Storage s = (Storage)i;
        s.Store("somestring"); // Prints Generic
        s.Store(1); // Prints Specific
    }
}

有没有办法让它在接口(interface)调用的时候使用专门版本的Store?如果不是,有人知道 C# 以这种方式处理泛型参数的确切原因吗?

编辑: 如果不是因为 C# 无法在多个步骤中解析模板参数,则可以解决该问题。

void Foo<T>(T t)
{
    SubFoo(t);
}

void SubFoo<T>(T t)
{
    Console.WriteLine("Generic");
}

void SubFoo(int t)
{
    Console.WriteLine("Specific");
}

在这里调用 Foo(1) 也会打印“Generic”,难道编译器不能解决这个问题吗?还是 JIT 会阻止这种情况?

最佳答案

重载解析是在编译时执行的,而不是在运行时根据传递值的实际类型执行的。

IStorage i = new Storage();
i.Store("somestring"); // Prints Generic
i.Store(1); // Prints Generic

这将始终调用“通用”方法,因为 IStorage 中只有一个 Store 重载,编译器不知道 i 实际上包含一个 Storage 对象。编译器如何知道 Storage 中的其他重载?

Storage s = (Storage)i;
s.Store("somestring"); // Prints Generic
s.Store(1); // Prints Specific

在这里,编译器知道 s 包含一个 Storage 对象(或从 Storage 派生的对象),因为 s 就是这样声明的。所以它看到两个重载。它为 int 值选择特定的重载,因为重载解析规则表明优先选择特定的重载而不是通用的重载。


技术上可以在运行时确定泛型方法中的 typeof(T) 并将方法调用转发给特定方法。但仔细想想,这并没有多大意义。通用方法意味着相同的实现适用于不同的、不相关类型的参数。如果您想要不同类型的不同实现,则不应为此使用泛型。


void Foo<T>(T t)
{
    SubFoo(t);
}

void SubFoo<T>(T t);
void SubFoo(int t);

泛型的工作方式与 C++ 模板有很大不同。 C# 编译器仅将 Foo 编译一次——编译为通用方法。请记住:通用意味着不同类型的相同实现。 C# 编译器在编译时不知道 T 是 int 还是 string 或任何其他类型。因此,适用于任何 T 的 Foo 的唯一可能实现是调用 SubFoo。如果根据 T 调用 SubFoo 重载之一,则 Foo 的实现对于所有 T 将不再相同。

关于C# 泛型接口(interface)特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2229084/

有关C# 泛型接口(interface)特化的更多相关文章

  1. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  2. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  3. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  4. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  5. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

  6. ruby - 可以像在 C# 中使用#region 一样在 Ruby 中使用 begin/end 吗? - 2

    我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用

  7. c# - Ruby 等效于 C# Linq 聚合方法 - 2

    什么是Linq聚合方法的ruby​​等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj

  8. c# - 先学什么? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭8年前。Improvethisquestion几年前我去学校学习编程,毕业后我找到了一份系统管理方面的工作,这就是我职业生涯的方向。我想重新开始某种开发,并且一直在“玩”C#和ASP.NET,但我已经听到很多关于其他"new"语言的讨论(新的意思是它们是新的)我)喜欢Ruby和F#。我想我想知道我是否在浪费时间学习主要的MS语言,而不是成为一名通才。很长一段时间没有离开开发社区(如果我曾经离开过的话)让我在潮流中挣扎,我不想落在时代的

  9. c# - 在 C# 中重现 Ruby OpenSSL private_encrypt 输出 - 2

    我有一个简单的Ruby脚本,我用它在某些HTTPheader上执行private_encrypt以签署要发送到ruby​​RESTAPI的Web请求,该API会根据Base64编码字符串测试Base64编码字符串生成而不是解码Base64和解密数据然后测试原始字符串。我使用的脚本是require"openssl"require"base64"path_to_cert=ARGV[0].dupplain_text=Base64.decode64(ARGV[1].dup)private_key=OpenSSL::PKey::RSA.new(File.read(path_to_cert))pu

  10. C# 的 LINQ 用于在 ruby​​ 中等效的集合操作 - 2

    我是ruby​​开发的新手,我目前正在使用rails2.3.11在ruby​​1.8.7中开发一个项目,我想知道这种语言是否有与C#的linq等效的集合操作,例如where子句。谢谢。 最佳答案 Ruby中Linq的where等价于find_all检查documentationfortheEnumerableModule用于其他功能。 关于C#的LINQ用于在ruby​​中等效的集合操作,我们在StackOverflow上找到一个类似的问题: https://

随机推荐