将C#4允许“动态铸造”?如果没有,C#应该支持吗?
-
03-07-2019 - |
题
我不是指将一个较低的接口或基类转换为更多派生类的意义上的动态转换,我的意思是采用我创建的接口定义,然后动态地向该接口转换另一个对象NOT从该接口派生但支持所有调用。
例如,
interface IMyInterface
{
bool Visible
{
get;
}
}
TextBox myTextBox = new TextBox();
IMyInterface i = (dynamic<IMyInterface>)myTextBox;
这可以在编译时针对已知类型实现,而运行时针对使用dynamic声明的实例实现。接口定义是已知的,类型(在此示例中)也是如此,因此编译器可以确定对象是否支持接口定义的调用,并为我们执行一些魔术以进行转换。
我的猜测是C#4不支持这个(我无法找到它的引用),但我想知道肯定。如果不是,我想讨论它是否应该包含在该语言的未来变体中,以及支持和反对的原因。对我来说,似乎是一个很好的补充,可以在代码中实现更大的多态性,而无需创建全新的类型来包装现有的框架类型。
<强>更新强>结果 为免有人指责我剽窃,我不知道 Jon Skeet已经提出过这个问题。但是,很高兴知道我们想到了非常相似的语法,这表明它至少可能是直观的。同时,“有一个独到的想法”。留在我的桶清单上另一天。
解决方案
我认为Jon Skeet有这样一个提议( http://msmvps.com/blogs/jon_skeet/archive/2008/10/30/c-4-0-dynamic-lt-t-gt.aspx ),但到目前为止,我还没有听说过C#4.0会有它。
其他提示
我认为这有问题。您正在引入两个未耦合的类之间的耦合。
请考虑以下代码。
public interface IFoo
{
int MethodA();
int MethodB();
}
public class Bar
{
int MethodA();
int MethodB();
}
public class SomeClass
{
int MethodFoo(IFoo someFoo);
}
那么这应该是合法的吗?
int blah = someClass.MethodFoo((dynamic<IFoo>)bar);
似乎它应该是合法的,因为编译器应该能够动态地将bar键入为实现IFoo的东西。
但是,此时您通过一个完全独立的代码部分中的调用来耦合IFoo和Bar。
如果您编辑Bar因为它不再需要MethodB,则突然someClass.MethodFood不再起作用,即使Bar和IFoo不相关。
以同样的方式,如果你向IFoo添加MethodC(),你的代码会再次中断,即使IFoo和Bar表面上没有相关性。
事实是,虽然这在你不能控制的对象之间存在相似性的特定情况下会很有用,但是有一个原因是接口必须显式地附加到对象上,原因是编译器可以保证对象实现它。
C#不需要支持它,因为它可以非常干净地实现为库。
我已经看过三到四个单独的实现(我在找到之前就开始自己编写一个)。这是我见过的最彻底的治疗方法:
将DLR集成到运行时后,可能会更容易实现。
因为给定接口的包装器/转发器类可以生成一次然后被缓存,然后一个未知类型的给定对象可以被包装一次,所以有很多用于缓存调用站点的空间,等等。表现应该非常好。
相比之下,我认为 dynamic
关键字是一种语言特征,而且是一个非常复杂的关键字,是一种不必要的,可能是灾难性的题外话,它曾经是一种以前非常有用的语言。清晰的静态打字理念,为未来的改进提供了明确的方向。他们应该坚持这一点,并使类型推断更好,更好,直到打字变得更加隐形。有很多领域他们可以在不破坏现有程序的情况下发展语言,但他们却没有,仅仅是因为资源限制(例如 var
不能在更多地方使用的原因是因为他们必须重写编译器并且他们没有时间)。
他们仍然在C#4.0(方差功能)中做得很好但是还有很多其他方法可以使类型系统在编译时检测问题时更智能,更自动,更强大。相反,我们基本上得到了一个噱头。
开源框架 Impromptu-Interface 使用C#4和dlr执行此操作
using ImpromptuInterface;
interface IMyInterface
{
bool Visible
{
get;
}
}
TextBox myTextBox = new TextBox();
IMyInterface i = myTextBox.ActLike<IMyInterface>();
由于它使用dlr,因此它也适用于ExpandoObject和DynamicObject。