English 中文(简体)
类型无法满足参数 TParam 上的新() 限制, 因为 TTParam 需要成员
原标题: Type cannot satisfy the new() constraint on parameter TParam because Type has required members
I have this class structure (simplified): public class InducingMedium { public required string File { get; set; } } public class InducingVideo : InducingMedium {} public class InducingAudio : InducingMedium {} Now, I want to generically instantiate an instance of a specific type: public abstract class BaseInducingTests where TMedium : InducingMedium, new() { protected async Task> CreateInducingMedia(IEnumerable files) { return files.Select(file => { // Do some processing... return new TMedium { File = file, }; }); } } public class InducingVideosTests : BaseInducingTests { } But in the derived class I get an error: Namespace.InducingVideo cannot satisfy the new() constraint on parameter TMedium in the generic class Namespace.Tests.BaseInducingTests because Namespace.InducingVideo has required members Is there any way to fix this without introducing reflection? I was really excited about required members, which work pretty well with nullable types, but now I see this has its own caveats :(
最佳回答
This is explicitly mentioned in the docs: A type with any required members may not be used as a type argument when the type parameter includes the new() constraint. The compiler can t enforce that all required members are initialized in the generic code. Either remove the required modifier or change the generic handling. For example provide factory via ctor: public abstract class BaseInducingTests where TMedium : InducingMedium { private readonly Func _init; public BaseInducingTests(Func init) { _init = init; } protected async Task> CreateInducingMedia(IEnumerable files) { return files.Select(file => _init(file)); } } public class InducingVideosTests : BaseInducingTests { public InducingVideosTests() : base(s => new InducingVideo{File = s}) { } } If needed you can then create a wrapper to support classes which satisfy new() constraint: public abstract class BaseNewableInducingTests : BaseInducingTests where TMedium : InducingMedium, new() { protected BaseNewableInducingTests() : base(s => new TMedium { File = s }) { } }
问题回答
Another workaround which I ve just found is SetsRequiredMembers attribute: public class InducingVideosTests : BaseInducingTests { } public class TestInducingVideo : InducingVideo { [SetsRequiredMembers] public TestInducingVideo() { } } This kind of defeats the purpose of required members, but so does reflection and for test purposes it s an easier way. Source: https://code-maze.com/csharp-required-members/
I started getting this error in Visual Studio Version 17.9.5 because Visual Studio automatically added required on save. This is due to Code Cleanup. Error CS9040 FilesResponse cannot satisfy the new() constraint on parameter T in the generic type or or method MyCode because FilesResponse has required members. Solved this by simply setting the class as nullable in cases where a new instance did not have every variable. In your case this would be: public class InducingMedium { public string? File { get; set; } }
Credit to this GitHub post where the author proposed "Allowing new() generic constraint to have some required members if the derived class has no extra required members". You cannot know if the inheritance tree of a type is complete at compile-time. Assemblies may be dynamically loaded at runtime. In the same post, a workaround is also proposed instead of using new(), use the new C# 11 static abstract interface member: public abstract class DefaultComponentParts { public required string Name { get; set; } public string? Description { get; set; } } public class ComponentCssProperty : DefaultComponentParts, INew { public static ComponentCssProperty New(string name) => new() { Name = name, }; } public class ComponentSlot : DefaultComponentParts, INew { public static ComponentSlot New(string name) => new() { Name = name, }; } public interface INew where T : DefaultComponentParts, INew { static abstract T New(string name); } // Usage: static List ParseComponentParts(JsonObject declarations, string partName) where T : DefaultComponentParts, INew { T.New(name) // When you need the T }




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签