ang*_*son 206
在dynamic加入关键字,用C#4.0的许多其他新功能一起,以使其更简单谈谈代码,住在或来自其他运行时,有不同的API.
举个例子.
如果你有一个COM对象,比如Word.Application对象,并且想要打开一个文档,那么执行该操作的方法不少于15个参数,其中大多数是可选的.
要调用此方法,您需要这样的东西(我正在简化,这不是实际的代码):
object missing = System.Reflection.Missing.Value;
object fileName = "C:\\test.docx";
object readOnly = true;
wordApplication.Documents.Open(ref fileName, ref missing, ref readOnly,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing);
Run Code Online (Sandbox Code Playgroud)
注意所有这些论点?你需要传递那些自C#之前的版本4.0之前没有可选参数的概念.在C#4.0中,通过引入以下内容使COM API变得更容易使用:
ref可选的COM API的上述调用的新语法是:
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
Run Code Online (Sandbox Code Playgroud)
看看它看起来多么容易,它的可读性有多大?
让我们分开:
named argument, can skip the rest
|
v
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
^ ^
| |
notice no ref keyword, can pass
actual parameter values instead
Run Code Online (Sandbox Code Playgroud)
神奇的是,C#编译器现在将注入必要的代码,并在运行时使用新类,几乎完成与之前完全相同的操作,但语法已被隐藏,现在您可以专注于什么,而不是如何.Anders Hejlsberg喜欢说你必须引用不同的"咒语",这是对整个事物的魔力的一种双关语,你通常需要挥动你的手并按照正确的顺序说出一些神奇的词语获得某种类型的咒语.与COM对象交谈的旧API方式很多,你需要跳过很多箍,以便哄骗编译器为你编译代码.
如果您尝试与没有接口或类的COM对象进行通信,那么在版本4.0之前的C#中会出现更多问题,您所拥有的只是一个IDispatch参考.
如果你不知道它是什么,IDispatch基本上是COM对象的反射.随着IDispatch你可以问对象接口"什么是被称为保存方法的身份证号码",并建立包含参数值的某些类型的数组,最后调用Invokeon方法IDispatch接口来调用方法,传递所有你设法收集到的信息.
上面的Save方法看起来像这样(这绝对不是正确的代码):
string[] methodNames = new[] { "Open" };
Guid IID = ...
int methodId = wordApplication.GetIDsOfNames(IID, methodNames, methodNames.Length, lcid, dispid);
SafeArray args = new SafeArray(new[] { fileName, missing, missing, .... });
wordApplication.Invoke(methodId, ... args, ...);
Run Code Online (Sandbox Code Playgroud)
所有这些只是打开一个文件.
很久以前,VB有可选的参数和对大多数开箱即用的支持,所以这个C#代码:
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
Run Code Online (Sandbox Code Playgroud)
基本上只是C#在表达性方面赶上VB,但通过使其可扩展,而不仅仅是COM,以正确的方式做到这一点.当然,这也适用于VB.NET或基于.NET运行时构建的任何其他语言.
您可以IDispatch在维基百科上找到有关界面的更多信息:IDispatch,如果您想了解更多相关信息.这真是血腥的东西.
但是,如果你想与Python对象交谈怎么办?与用于COM对象的API相比,它有一个不同的API,并且由于Python对象本质上也是动态的,因此您需要求助于反射魔法来找到正确的调用方法,它们的参数等,而不是.NET.反射,为Python编写的东西,非常像上面的IDispatch代码,只是完全不同.
而对于Ruby?还有一个不同的API.
JavaScript的?相同的交易,不同的API也是如此.
动态关键字包含两件事:
dynamicdynamic关键字所需的特定API ,并将调用映射到正确的处理方式.API甚至是文档化的,因此如果您有来自未涵盖的运行时的对象,则可以添加它.dynamic但是,该关键字不是要替换任何现有的仅.NET代码.当然,你可以做到这一点,但由于这个原因没有添加,并且前面的Anders Hejlsberg的C#编程语言的作者最坚定的是他们仍然认为C#是一种强类型语言,并且不会牺牲那个原则.
这意味着虽然您可以编写如下代码:
dynamic x = 10;
dynamic y = 3.14;
dynamic z = "test";
dynamic k = true;
dynamic l = x + y * z - k;
Run Code Online (Sandbox Code Playgroud)
并且让它编译,它并不意味着一种魔术 - 让我们想出你在运行时意味着什么样的系统.
整个目的是让它更容易与其他类型的对象交谈.
互联网上有很多关于关键词,支持者,反对者,讨论,咆哮,赞美等的资料.
我建议你从以下链接开始,然后谷歌更多:
Pra*_*ana 178
dynamic关键字是C#4.0的新增内容,用于告诉编译器变量的类型可以更改,或者直到运行时才知道它.可以将其视为能够与Object进行交互而无需进行转换.
dynamic cust = GetCustomer();
cust.FirstName = "foo"; // works as expected
cust.Process(); // works as expected
cust.MissingMethod(); // No method found!
Run Code Online (Sandbox Code Playgroud)
请注意,我们不需要转换或声明cust类型为Customer.因为我们将其声明为动态,所以运行时接管然后搜索并为我们设置FirstName属性.当然,现在,当您使用动态变量时,您放弃了编译器类型检查.这意味着调用cust.MissingMethod()将编译,直到运行时才会失败.此操作的结果是RuntimeBinderException,因为未在Customer类上定义MissingMethod.
上面的示例显示了调用方法和属性时动态的工作原理.另一个强大(并且具有潜在危险)的功能是能够为不同类型的数据重用变量.我确信那里的Python,Ruby和Perl程序员可以想出一百万种方法来利用这一点,但我一直在使用C#,以至于它对我来说感觉"错误".
dynamic foo = 123;
foo = "bar";
Run Code Online (Sandbox Code Playgroud)
好的,所以你很可能不会经常像上面那样编写代码.但是,有时候,变量重用可以派上用场,或者清理一堆脏代码.我经常遇到的一个简单案例是不断地在十进制和双精度之间进行转换.
decimal foo = GetDecimalValue();
foo = foo / 2.5; // Does not compile
foo = Math.Sqrt(foo); // Does not compile
string bar = foo.ToString("c");
Run Code Online (Sandbox Code Playgroud)
第二行不编译,因为2.5被输入为double而第3行没有编译,因为Math.Sqrt需要一个double.显然,您所要做的就是强制转换和/或更改变量类型,但可能存在动态使用的情况.
dynamic foo = GetDecimalValue(); // still returns a decimal
foo = foo / 2.5; // The runtime takes care of this for us
foo = Math.Sqrt(foo); // Again, the DLR works its magic
string bar = foo.ToString("c");
Run Code Online (Sandbox Code Playgroud)
阅读更多功能:http://www.codeproject.com/KB/cs/CSharp4Features.aspx
Ste*_*dis 27
我很惊讶没人提到多次派遣.解决这个问题的常用方法是通过访问者模式,但这并不总是可行的,因此您最终会进行堆叠is检查.
所以这是我自己应用的真实例子.而不是做:
public static MapDtoBase CreateDto(ChartItem item)
{
if (item is ElevationPoint) return CreateDtoImpl((ElevationPoint)item);
if (item is MapPoint) return CreateDtoImpl((MapPoint)item);
if (item is MapPolyline) return CreateDtoImpl((MapPolyline)item);
//other subtypes follow
throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}
Run Code Online (Sandbox Code Playgroud)
你做:
public static MapDtoBase CreateDto(ChartItem item)
{
return CreateDtoImpl(item as dynamic);
}
private static MapDtoBase CreateDtoImpl(ChartItem item)
{
throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}
private static MapDtoBase CreateDtoImpl(MapPoint item)
{
return new MapPointDto(item);
}
private static MapDtoBase CreateDtoImpl(ElevationPoint item)
{
return new ElevationDto(item);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在第一种情况下ElevationPoint是子类,MapPoint如果它没有放在它之前 MapPoint永远不会到达.动态不是这种情况,因为将调用最接近的匹配方法.
正如您可能从代码中猜到的那样,当我从ChartItem对象执行到可序列化版本的转换时,该功能非常方便.我不想让访问者污染我的代码,我也不想ChartItem用无用的序列化特定属性来污染我的对象.
Phi*_*ier 11
它使静态类型语言(CLR)更容易与在DLR(动态语言运行时)上运行的动态类型(python,ruby ...)进行互操作,请参阅MSDN:
例如,您可以使用以下代码在C#中增加XML中的计数器.
Run Code Online (Sandbox Code Playgroud)Scriptobj.SetProperty("Count", ((int)GetProperty("Count")) + 1);通过使用DLR,您可以使用以下代码代替相同的操作.
Run Code Online (Sandbox Code Playgroud)scriptobj.Count += 1;
MSDN列出了这些优点:
- 简化将动态语言移植到.NET Framework的过程
- 启用静态类型语言中的动态功能
- 提供DLR和.NET Framework的未来优势
- 实现库和对象的共享
- 提供快速动态调度和调用
有关详细信息,请参阅MSDN.
使用示例:
您使用了许多具有公共属性 'CreationDate' 的类:
public class Contact
{
// some properties
public DateTime CreationDate { get; set; }
}
public class Company
{
// some properties
public DateTime CreationDate { get; set; }
}
public class Opportunity
{
// some properties
public DateTime CreationDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您编写一个公共方法来检索 'CreationDate' 属性的值,则必须使用反射:
static DateTime RetrieveValueOfCreationDate(Object item)
{
return (DateTime)item.GetType().GetProperty("CreationDate").GetValue(item);
}
Run Code Online (Sandbox Code Playgroud)
使用“动态”概念,您的代码更加优雅:
static DateTime RetrieveValueOfCreationDate(dynamic item)
{
return item.CreationDate;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
138611 次 |
| 最近记录: |