请进一步了解主要更新!
我有一些像这样的代码:
void Test(IEnumerable x)
{
var dynX = x.Cast<dynamic>();
var result = dynX.Select(_ => _.Text);
}
在针对.NET 4.5的现有库项目中。 VS2015的IntelliSense强调了Text
部分,抱怨说:'object'不包含'Text'的定义......
果然,编译失败了
错误CS1061:'object'不包含'Text'的定义,也没有扩展方法'Text'可以找到接受'object'类型的第一个参数(你是否缺少using指令或汇编引用?)
此消息总是显示'object'
,即使我将演员表更改为.Cast<IAsyncResult>()
或诸如此类的东西。当我将lambda参数悬停时,工具提示显示类型IColumn
(存在但不相关)。再说一遍,无论我演绎什么类型。
但是,当我将Select()
方法悬停时,它会正确显示参数Func<dynamic, dynamic>
。如果我明确指定lambda参数类型,它将编译。如果我明确指定Select()
上的类型参数,它也可以。
LINQ与dynamic
的其他用法正在发挥作用。当我将此方法复制到解决方案中的另一个(现有)项目时,它也会编译。当我将它复制到同一项目中的另一个文件时,它不会编译。
它也与VS2013一起编译。
在Windows 8.1和Windows 10中,所有同事都会出现同样的错误。
也许这是类型推断的一些奇怪问题......?
我尝试的事情没有帮助:
更新
好吧,我设法创建了一个自包含的最小失败的示例:
static class Program
{
static void Main(string[] args)
{
IEnumerable x = new object[0];
IEnumerable<dynamic> dynX = x.Cast<dynamic>();
// CS1061 'object' does not contain a definition for 'Text'...
// var tooltip shows IColumn instead of IEnumerable<dynamic>
var result = dynX.Select(_ => _.Text);
}
public static IColumn Select<TResult>(this IColumn source, Func<object, TResult> selector)
{
throw new NotImplementedException();
}
}
public interface IColumn { }
从我的看法来看,这清楚地表明VS2015 /新编译器版本如何解决扩展方法存在严重错误。
以下内容只是松散相关,主要是关于误导性的错误消息。我决定不让评论混淆。
更糟糕的是,即使IEnumerable
和object
都没有可能有扩展方法Select()
,这些也会失败并出现同样的错误:
// CS1061 'object' does not contain a definition for 'Text'
// var tooltip shows IColumn
var result2 = x.Select(_ => _.Text);
object o = new object();
// CS1061 'object' does not contain a definition for 'Text'
// var tooltip shows IColumn
var result3 = o.Select(_ => _.Text);
附录
现在可以在Roslyn bug tracker上跟踪此问题。
答案 0 :(得分:1)
无法说明为什么它在一个VS而不是另一个VS中起作用,但这就是我要做的事情
重命名。
public static IColumn Select<TResult>(this IColumn source, Func<object, TResult> selector)
{
throw new NotImplementedException();
}
&#34;选择&#34;是其他常见lib的方法名称的内置版本。 所以我强烈建议你将它重命名为&#34; AppColumnSelectText&#34;或者什么,但不是&#34;选择&#34;。
然后改变
public interface IColumn { }
到
public interface IColumn
{
string Text {get; set;}
}
然后实现它
public class MyClass : IColumn
{
public string Text { get; set;}
}
然后将动态转换为IColumn,假设它来自MyClass类类型
var columns = fields.Select(a => new {a as IColumn}).ToList();
然后你就能做到
var result3 = columns.AppColumnSelectText(x => x.Text);
我知道这可能不是你想要的,但编程更清晰,你可以存档相同的结果。
请阅读以下内容并发表评论,希望这能描绘得更好。
public static class Test
{
public static IColumn Select<TResult>(this IColumn source, Func<object, TResult> selector)
{
throw new NotImplementedException();
}
public static IColumn SelectOtherColumn<TResult>(this IColumn source, Func<IColumn, TResult> selector)
{
throw new NotImplementedException();
}
}
public interface IColumn
{
string Text { get; set; }
}
public class Program
{
private static void Main(string[] args)
{
IEnumerable ojb = new object[0];
IEnumerable<dynamic> dynX = ojb.Cast<dynamic>();
// CS1061 'object' does not contain a definition for 'Text'...
// var tooltip shows IColumn instead of IEnumerable<dynamic>
//NB this is the System.Linq.Select
var result = dynX.Select(x => x.Text);
var xzy = dynX as IColumn;
//converstion here will probably FAIL so this makes this pointless.
//here the compliter complains as the Type object has no Text Prop as it was not sepcified anywhere
var theThingyouwant1 = xzy.Select(x => x.Text);
//here you are OK as the complier can infer something
var theThingyouwant2 = xzy.SelectOtherColumn(x => x.Text);
}
}
<强>更新强> 更进一步......见下面的插图
public class MyType
{
public string Text { get; set; }
public string SomethingEsle { get; set; }
}
public class Program
{
private static void Main(string[] args)
{
List<MyType> ojb = new List<MyType>();
ojb.Add(new MyType {Text = "OMG", SomethingEsle = "cat"});
//dynX is a dynamic...
var dynX = ojb.Select(x => new {x.Text, x.SomethingEsle}).ToList();
//NB this is the System.Linq.Select
//this now works as the complier can determine that there is a property Text
var result = dynX.Select(x => x.Text).ToList();
}
}
你可以使用你的Select ...但它只适用于实现IColumn的东西,这就是为什么我很难看出它是如何工作的。
答案 1 :(得分:0)
您可以使用此
static void Main(string[] args)
{
//IEnumerable x = new object[0];
//var result2 = x.Select(_ => _.Text);
//Compile time Error "Enumerable" does not contain a definition for 'Select' and no extension method
// because IEnumerable is not a generic class
IEnumerable<object> x = new object[0];
var result2 = x.Select(_ => _.Text);
}
答案 2 :(得分:0)
这只是一种情况,c#使用一种鸭子类型来允许LINQ适用于任何类型。
我将从一个简单的例子开始。
如果我定义了一个类Foo
行:
public class Foo
{
public int Bar;
public int Select(Func<Foo, int> map)
{
return map(this);
}
}
然后我可以编写这段代码:
Foo foo = new Foo() { Bar = 42 };
int query =
from f in foo
select f.Bar;
我得到的LINQ版本适用于返回Foo
(不是IEnumerable<T>
)的int
类型(不是IEnumerable<R>
)。
可以通过这种方式专门定义所有LINQ运算符。
上面的例子也可以写成:
public class Foo
{
public int Bar;
}
public static class Ex
{
public static int Select(this Foo source, Func<Foo, int> selector)
{
return selector(source);
}
}
现在它看起来像你的代码。
所以如果我们做出这个改变:
public class Foo
{
}
public static class Ex
{
public static IColumn Select<TResult>(this IColumn source, Func<object, TResult> selector)
{
throw new NotImplementedException();
}
}
public interface IColumn { }
然后此代码失败并出现与您相同的错误:
IEnumerable<dynamic> foo = new [] { new Foo() };
var query =
from f in foo
select f.Text;
如果我再做这个改变:
public static class Ex
{
public static IColumn Select<TSource, TResult>(this IColumn source, Func<TSource, TResult> selector)
{
throw new NotImplementedException();
}
}
现在代码报告“RuntimeBinderException:'Foo'不包含'Text'的定义。”
我们最终完成的工作是显示编译器尝试使用您的Select
方法实现LINQ Select
运算符。然后,它会尝试查看是否可以使用已定义的Select
方法作为所显示类型的重载,并且由于dynamic
可以“强制转换”为IColumn
,它会显示您的Select
方法是最好的超载。此外,由于编译器只搜索当前类中的候选者,因此不会继续查找标准LINQ运算符。
当然,然后编译器使用您的重载将dynamic
强制转换为object
,然后尝试查找.Text
属性。它当然不能,所以它会报告你的错误。
答案 3 :(得分:0)
好吧,看看the bug report已经解决了很长时间了,让我们总结一下:
这是一个错误,编译器没有按原样应用dynamic
标志,导致它变为object
。该错误已得到修复。我不知道VS2015何时可以使用,也许其他人可以提供这些信息。
这可能会在重载解析机制中引发一些怪癖,导致误导性错误消息和工具提示内容。