类型无法满足参数 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
}
相关问题
What is the use of `default` keyword in C#?
What is the use of default keyword in C#?
Is it introduced in C# 3.0 ?
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 ...
ADO.NET Entity Framework Association of Entities by Value Range
I have two EF entities. One has a property called HouseNumber. The other has two properties, one called StartHouseNumber and one called EndHouseNumber.
I want to create a many to many association ...
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, ...
What is the most efficient keyvalue pair for ordering?
Since I cannot order my dictionary, what is the best way of going about taking key value pairs and also maintaing an index?
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.
...