C#4.0进一步扩展了通用类型和接口的协方差和逆变.有些接口(比如IEnumerable<T>)是协变量,所以我可以这样做:
IEnumerable<object> ie = new List<string>();
Run Code Online (Sandbox Code Playgroud)
但是这条线怎么样?我遇到了编译时错误
List<Object> list = new List<String>();
//Cannot implicitly convert type List<string>' to List<object>'
Run Code Online (Sandbox Code Playgroud)
我的意思是,如果List<T>实现IEnumerable<T>为什么List<T>仍然是不变的?有没有一个很好的反例可以解释为什么在C#中不允许这样做?
我真的很喜欢使用C#5.0异步编程.但是,有些地方更新旧代码以与TAP模型保持一致会给我带来问题.
这是其中之一 - 我不确定为什么Task<TResult>在TResult中没有协变,但是在尝试更新协变接口以从同步模式转换为异步模式时,它会给我带来问题:
旧代码:
public interface IInitializable<out T> // ** out generic modifier **
{
/// <summary>
/// Boolean to indicate if class is ready
/// </summary>
bool IsInitialized { get; }
/// <summary>
/// Calls for instance to be initialized using current parameters
/// Driver initialization can be done in the default constructor if desired
/// </summary>
T Initialize();
}
Run Code Online (Sandbox Code Playgroud)
新代码(不会编译):
public interface IAsyncInitializable<out T> // ** out generic modifier...broken **
{
/// <summary>
/// Boolean …Run Code Online (Sandbox Code Playgroud) 考虑以下情况:
class A
{
public int Id;
}
class B : A
{
}
class Main
{
public async Task<int> Create(Type type)
{
MethodInfo method = this.GetType().GetMethod("Create", new Type[] { typeof(string) }).MakeGenericMethod(new Type[] { type });
A a = await (Task<A>)method.Invoke(this, new object[] { "humpf" });
return a.Id;
}
public async Task<T> Create<T>(string name) where T : A
{
T t = await Foo.Bar<T>(name);
return t;
}
}
Run Code Online (Sandbox Code Playgroud)
呼叫new Main().Create(typeof(B))将失败
无法将'
System.Threading.Tasks.Task[B]'类型的对象强制转换为'System.Threading.Tasks.Task[A]'
我不太明白,因为在这种情况下,Generic Create<T>方法只返回始终从' …
鉴于以下片段,我完全不明白为什么即将实现的目标是不可能的:
接口:
public interface IEntityRepository<out T> : IRepository<IEntity> {
void RequeryDataBase();
IEnumerable<T> Search(string pattern);
Task<IEnumerable<T>> SearchAsync(string pattern);
SearchContext Context { get; }
string BaseTableName { get; }
}
Run Code Online (Sandbox Code Playgroud)
In IRepository<IEntity>只是简单的通用CRUD定义.
我在这一行得到错误: Task<IEnumerable<T>> SearchAsync(string pattern);
错误:
方法返回类型必须输出安全.无效方差:类型参数T必须在Task上无效
请帮我明白了,为什么我不能使用<out T>了Task<T>
我需要更深入地了解Func类型表达式.
public class TheResult : IResultEntry {
...
}
Run Code Online (Sandbox Code Playgroud)
上面的类,为什么下面的第二种方法需要演员?
我当然可以阅读错误信息,但很难理解.
// Success
public Task<IResultEntry> ProcessAsync_1()
{
return Task.Factory.StartNew(() => (IResultEntry) new TheResult());
}
// Fail: Compiler error. Cannot implicitly convert...
public Task<IResultEntry> ProcessAsync_2()
{
return Task.Factory.StartNew(() => new TheResult());
}
Run Code Online (Sandbox Code Playgroud)
如果我们在ReSharper的帮助下将其更改为命名方法,我们可以不进行强制转换.
public Task<IResultEntry> ProcessAsync_2_Changed()
{
return Task.Factory.StartNew(function);
}
private IResultEntry function()
{
return new TheResult();
}
Run Code Online (Sandbox Code Playgroud) 我有以下程序:
async Task Main()
{
IList<int> myList = await TestAsync();
}
public Task<IList<int>> TestAsync()
{
return Task.FromResult(new List<int>());
}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨它无法在方法中将Task<List>a转换为 a :Task<IList>TestAsync
CS0029 无法将类型隐式转换
System.Threading.Tasks.Task<System.Collections.Generic.List<int>>为System.Threading.Tasks.Task<System.Collections.Generic.IList<int>>
为什么它不知道我的方法返回 IList 的任务?
我正在尝试从通用函数 ( ) 返回特定类型的值GenericGetter。
当我尝试简单地返回Task来自 的键入结果时GenericGetter,编译器向我显示以下错误:
Cannot convert expression type 'System.Threading.Tasks.Task<Example.ChildClass>'
to return type 'System.Threading.Tasks.Task<Example.BaseClass>'
Run Code Online (Sandbox Code Playgroud)
GenericGetter但是,如果我创建包含call 的函数async,并且返回等待的值,则编译器不会介意。它可以编译,可以工作,但对我来说,添加的 async/await 似乎是多余的。
GetChildClass不编译,而却GetChildClassAsync 编译?这是我的例子:
namespace Example
{
public class BaseClass {}
public class ChildClass : BaseClass {}
public class MyExample
{
private async Task Main()
{
var foo = await GetChildClass().ConfigureAwait(false);
var bar = await GetChildClassAsync().ConfigureAwait(false);
}
private Task<BaseClass> GetChildClass() =>
GenericGetter<ChildClass>();
private async Task<BaseClass> GetChildClassAsync() =>
await GenericGetter<ChildClass>().ConfigureAwait(false); …Run Code Online (Sandbox Code Playgroud) 我有以下方法:
public async Task Execute()
{
object previous = null;
// _delegates is of type IReadOnlyCollection<Delegate>
foreach (Delegate method in _delegates)
{
Task executing = (Task) (previous != null
? method.DynamicInvoke(_repository, previous)
: method.DynamicInvoke(_repository);
await executing;
// pseudo code here
if (executing returns something)
previous = executing.Result //<-- ?
else
previous = null;
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,我遍历按顺序执行的代表列表。每个委托都会接收一个存储库作为参数,以及前一个委托的返回值(如果有)。
有些代表返回a Task,有些代表返回a Task<TResult>。如果遇到后者,我想将TResult值存储在其中,previous以便将其作为参数传递给下一个委托。
有没有办法做到这一点?
我有这个代码:
static List<string> lst = new List<string>();
public static Task<IEnumerable<String>> GetStrings() {
IEnumerable<String> x = lst;
// This line below compiles just fine.
// return Task.Run(() => x);
// This line gives a compiler error:
// Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List<string>>' to
// 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<string>>'
return Task.Run(() => lst);
}
Run Code Online (Sandbox Code Playgroud)
为什么这一行编译得很好:return Task.Run(() => x);
虽然return Task.Run(() => lst);给出了编译器错误:
无法将类型“System.Threading.Tasks.Task<System.Collections.Generic.List>”隐式转换为“System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable>”
我认为既然List<string>是IEnumerable<string>,我不应该显式设置x. 我的意思是,编译器知道lst是一个IEnumerable<string>.
我想我一定在这里遗漏了一些基本的东西。
c# ×9
async-await ×4
covariance ×3
generics ×2
task ×2
.net ×1
asynchronous ×1
c#-4.0 ×1
c#-5.0 ×1
delegates ×1
func ×1
ienumerable ×1
lambda ×1
reflection ×1