【问题标题】:Cast an anonymous type with same properties to an interface [duplicate]将具有相同属性的匿名类型转换为接口[重复]
【发布时间】:2017-05-23 13:59:38
【问题描述】:

我正在尝试将具有相同属性的匿名类型转换为接口,但出现错误:

无法将“f__AnonymousType104`1[System.Int32]”类型的对象转换为“IHasFiles”类型。

 public interface IHasFiles
 {
    int FileMasterId { get; }
 }

 var entity = new { FileMasterId = fileMasterId }.CastOrDefault<IHasFiles>();
 // This is the line where I get the error

【问题讨论】:

  • 不确定这是否是问题所在,但您在此处使用属性设置器:FileMasterId = fileMasterId。在您的界面中,您刚刚获得了一个 Getter。
  • 问题是匿名对象不实现了那个接口,所以你不能转换它。 c# 不做鸭子类型,所以你唯一的选择是从你的匿名对象创建一个新对象,并确保新对象是实现接口的类型。
  • @Sebi 好像不是,我已经在界面中添加了setter,但仍然出现同样的错误。
  • 它应该使用继承自 IHasFiles 的具体类型。
  • 严格来说不是接口,而是public static THasFiles Cast&lt;THasFiles&gt;(this dynamic anonType) where THasFiles : IHasFiles, new() { THasFiles result = new THasFiles(); foreach(var prop in typeof(THasFiles).GetProperties().Where(property =&gt; anonType.GetType().GetProperty(property.Name) != null))) { prop.SetValue(result, anonType.GetType().GetProperty(property.Name).GetValue(anonType)); } return result }

标签: c# anonymous-types


【解决方案1】:

那是因为接口实现是显式,而不是动态。

您不能仅仅因为对象具有相同的成员而将对象强制转换为接口引用,该对象的类型也必须显式地实现接口。

除了object、dynamic(伪装成object)或它自己的类型之外,匿名类型不能转换为任何类型,这也有点棘手,因为你不完全知道类型(但是有... hacks)。

所以不,你不能那样做。

您要查找的内容通常称为“鸭子打字”,也就是“如果它像鸭子一样走路,如果它像鸭子一样嘎嘎叫,那么出于所有意图和目的,它是 一只鸭子”。普通 C# 或 .NET 不支持此功能,但可以使用代码“模仿”。

如果您需要一个实现特定接口的对象,您必须声明一个实现该接口的普通命名类型,没有(good) 解决方法。


现在,直到这里,这篇文章只是指 C# 编译器和/或 .NET 将允许您执行的操作。这里还有另一个概念,即使 C# 编译器允许您这样做,也会使 concept 变得模糊。

这就是意图。

接口执行以下操作:

  • 声明实施者必须向成员提供什么的合同
  • 就用户对可用成员的期望签订合同
  • 就这些成员的含义声明合同

这最后一部分很难强加到一个类型上,即使你可以在它的头上穿线一个接口。如果我编写的类恰好与您的一个接口具有相同的成员,如果您将该接口线程化到我的类上,您能否对这些成员施加相同的含义?

不,你不能。


现在,显然,有种方法可以绕过它,但没有一种是容易的,我会说在大多数情况下,它们都是隐藏糟糕设计的黑客。

无论如何,为了避免这种情况,您可以通过反射构建另一种类型,该类型同时将所有成员包装并委托给您的对象类型,并在运行时实现此接口 .

这是好的设计吗?不,绝对不是。

如果您真的想要走这条路,您可以使用“ImpromptuInterface”nuget 包,如下所述,您的代码将如下所示:

var entity = new { FileMasterId = fileMasterId }.ActLike<IHasFiles>();

但我会强烈建议不要这样做。声明类型!

【讨论】:

  • 至少对于IEnumerable,C# 确实依赖于duck-typing
  • 我想说添加类似“impromptu-interface”nuget 包的内容并添加一个“ActLike”语句很容易。
  • 是的,.NET 中的某些情况现在使用与鸭子类型相同的概念实现,await 是一种,foreach 是另一种。
  • 非常有用的帖子,学到了很多,干杯!
猜你喜欢
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多