Forcing the user to use the correct general method in C #

This may be a stupid question, but please help him answer. I currently have an interface with two generic methods:

ValidationResult Validate<T>(T t); IList<ValidationResult> ValidateList<T>(IEnumerable<T> entities); 

I want you to check the object, use the Validate method; if you want to check the array of an object, use the ValidateList method, which is pretty straightforward and straightforward. But it looks like the user can also use the Validate method to list objects without compiler errors (of course!). Are there any ways to limit them to the ValidateList method? Thank you so much.

+6
source share
4 answers

You can restrict a function to specific types of objects (and its derivatives) by doing something like this in a function declaration:

 ValidationResult Validate<T>(T t) where T : ValidateBase, ValidateBaseOther 

edit:

therefore, in this case, the function will only accept objects that are ValidateBase or its derivatives, or ValidateBaseOther or its derivatives. You can, of course, just use one if you want

 ValidationResult Validate<T>(T t) where T : ValidateBase 
+2
source

In short, you cannot solve your problem (prevent IEnumerable<> from being passed to the general method) using generics. This is because you cannot have negative common constraints (i.e., Everything except someClass ). The only reason common restrictions exist is to let the compiler know what signature to expect for a generic type. It should not provide development-time hints to the developer.

In addition to any unspecified external requirements, you can define your general type in an interface, not in a method. This does not guarantee that T cannot implement IEnumerable<> ; however, it ensures that the ValidateList must accept a list of what is passed to Validate . This means that T can be an array, but this will force the ValidateList to accept an array of arrays.

If you leave generic types at the method level, although they both have a generic type named T , these types actually have nothing to do with each other.

A generic type defined in an interface.

 public interface ISomeInterface<T> { ValidationResult Validate(T t); IList<ValidationResult> ValidateList(IEnumerable<T> entities); } 

This will be implemented as:

 public class SomeClass<T> : ISomeInterface<T> { ValidationResult Validate(T t) { // Do something ... } IList<ValidationResult> ValidateList(IEnumerable<T> entities) { // Do something ... } } 

And used like this:

 var myInstance = new SomeClass<int>(); int obj = 5; int arr = new [] {1,2,3}; myInstance.Validate(obj); myInstance.ValidateList(arr); myInstance.Validate(arr); // should throw compiler error 
-1
source

Since no better option has been found: Check to see if the Validate type implements IEnumerable<> . If so, an exception may occur ....

So here it is:

 ValidationResult Validate(T t) { Type OutResultNotUsed; if (typeof(T).IsOrInherits(typeof(IEnumerable<>), out OutResultNotUsed)) throw new Exeption("glkjglkjsdg"); } 

An extension method to check if any type of Is or Inherits is a general definition.

  public static bool IsOrInheritsGenericDefinition(this Type ThisType, Type GenericDefinition, out Type DefinitionWithTypedParameters) { DefinitionWithTypedParameters = ThisType; while (DefinitionWithTypedParameters != null) { if (DefinitionWithTypedParameters.IsGenericType) { if (DefinitionWithTypedParameters.GetGenericTypeDefinition() == GenericDefinition) return true; } DefinitionWithTypedParameters = DefinitionWithTypedParameters.BaseType; } return false; } 
-1
source

You can do the following:

 public class MultipleValidationResults : ValidationResult, IList<ValidationResult> { // stuff... } public ValidationResult Validate<T>(T t) { if (t is IEnumerable) // use reflection to call return ValidateList<Y>(t) // (T is IEnumerable<Y>) // other stuff } MultipleValidationResults ValidateList<T>(IEnumerable<T> entities); 
-1
source

Source: https://habr.com/ru/post/944370/


All Articles