Is it possible to have a non-public parameterless

2019-02-28 14:48发布

问题:

I have a following POCO class. I don not want the parameterless constructor to be public.

public class FileDownloadRequest
    {
       //public FileDownloadRequest() { }
        public FileDownloadRequest(int fileId, RepositoryFolderTypes fileType) //RepositoryFolderTypes is an enum, not a class
        {
            this.FileId = fileId;
            this.FileType = fileType;
        }
        public int FileId { get; set; }
        public RepositoryFolderTypes FileType { get; set; } //an enum
    }

When I am trying a https://10.27.8.6/Files/DownloadFile?fileId=1&folderType=SRC request to the following controller action, I get an error saying that no parameterless constructor exists for this object.

[HttpGet]
public async Task<HttpResponseMessage> DownloadFile([FromUri] FileDownloadRequest request)
{
}

Is it possible to have a non-public constructor, or is a public one absolutely required?

回答1:

Yes, you can use any constructor you like, but you will have to do the model binding yourself then. The problem is in DefaultModelBinder.CreateModel, which uses a parameterless public constructor.

You have to override the default model binder and create your own. If that is worth the time is up to you.

Steps to take:

  • Override CreateModel;
  • Check the modelType for some generic constraint which models you need to call the constructor with parameters on;
  • Call Activator.CreateInstance(Type, Object[]) with the parameters. You could obtain their values from the bindingContext;
  • Register the model binder, either through the ModelBinder attribute, or globally.

Read more on custom bindings here.



回答2:

Also, while Patrick's answer is great and shows how to do it (in scenarios where this much effort really makes sense), I just add something I've noticed in another SO post.

Basically, mark the parameterless constructor as [Obsolete("Comment to indicate its for binding only")] and that will prevent others from accidentally calling the parameterless one. (Thus showing explicitly which properties are required by the request object)