我有这个类结构(简化):
public class InducingMedium
{
public required string File { get; set; }
}
public class InducingVideo : InducingMedium {}
public class InducingAudio : InducingMedium {}
现在,我想一般实例化特定类型的实例:
public abstract class BaseInducingTests<TMedium>
where TMedium : InducingMedium, new()
{
protected async Task<IEnumerable<TMedium>> CreateInducingMedia(IEnumerable<string> files)
{
return files.Select(file =>
{
// Do some processing...
return new TMedium
{
File = file,
};
});
}
}
public class InducingVideosTests : BaseInducingTests<InducingVideo>
{
}
但是在派生类中我收到错误:
'Namespace.InducingVideo' cannot satisfy the 'new()' constraint
on parameter 'TMedium' in the generic class 'Namespace.Tests.BaseInducingTests<TMedium>'
because 'Namespace.InducingVideo' has required members
有没有办法在不引入反射的情况下解决这个问题?
我对
required
成员感到非常兴奋,它可以很好地处理可空类型,但现在我发现它有自己的警告:(
这在docs中明确提到:
当类型参数包含 new() 约束时,具有任何必需成员的类型不能用作类型参数。编译器无法强制在通用代码中初始化所有必需的成员。
删除
required
修饰符或更改通用处理。例如通过ctor提供工厂:
public abstract class BaseInducingTests<TMedium>
where TMedium : InducingMedium
{
private readonly Func<string, TMedium> _init;
public BaseInducingTests(Func<string, TMedium> init)
{
_init = init;
}
protected async Task<IEnumerable<TMedium>> CreateInducingMedia(IEnumerable<string> files)
{
return files.Select(file => _init(file));
}
}
public class InducingVideosTests : BaseInducingTests<InducingVideo>
{
public InducingVideosTests() : base(s => new InducingVideo{File = s})
{
}
}
如果需要,您可以创建一个包装器来支持满足
new()
约束的类:
public abstract class BaseNewableInducingTests<TMedium> : BaseInducingTests<TMedium>
where TMedium : InducingMedium, new()
{
protected BaseNewableInducingTests() : base(s => new TMedium { File = s })
{
}
}
我刚刚发现的另一个解决方法是
SetsRequiredMembers
属性:
public class InducingVideosTests : BaseInducingTests<TestInducingVideo>
{
}
public class TestInducingVideo : InducingVideo
{
[SetsRequiredMembers]
public TestInducingVideo()
{
}
}
这违背了
required
成员的目的,但反思也是如此,并且出于测试目的,这是一种更简单的方法。
我开始在 Visual Studio 版本 17.9.5 中收到此错误,因为 Visual Studio 在保存时自动添加了
required
。这是由于代码清理所致。
错误 CS9040“FilesResponse”无法满足“new()”约束 泛型类型或方法“MyCode”中的参数“T”,因为 “FilesResponse”需要成员。
在新实例没有每个变量的情况下,通过简单地将类设置为可为空来解决这个问题。在你的情况下,这将是:
public class InducingMedium
{
public string? File { get; set; }
}