Is it possible to ignore a generic type in a C # interface?

Background

I am starting work on a small OSS library called Sieve.NET .

A signature allows someone to define Sieve as follows:

 new EqualitySieve<ABusinessObject>().ForProperty(x => x.AnInt); 

This actually returns Sieve<ABusinessObject, int> , but I did my best to prevent users from taking too much care of this part.

Task

I would like to find a way to put an interface on it where I don’t need a property type at all - only it is consistent in everything.

So essentially, I would like to be able to declare ISieve<TFilterObjectType> , and also have that interface to define:

 ISieve<TFilterObjectType, TTypeIDontCareAbout> ForValue(TTypeIDontCareAbout); 

My goal is to have a class consisting of ISieve<ABusinessObject> , not ISieve<ABusinessObject, int> .

Question

  • Is there a way for an interface to declare a type that is effectively a wildcard, and says: "I don't care what type it is, only that it is consistent?"

My initial research says no, but I hope it turns out to be erroneous.

Updates and Clarifications

I am really trying to understand:

  • I allow users to create EqualitySieve<ABusinessObject>().ForProperty(x=>x.AnInt) .
  • This actually returns the user EqualitySieve<ABusinessObject, int> , but since this is a free interface, I remove them from the need to take care of this part.
  • I would like EqualitySieve , LessThanSieve etc. implement ISieve<ABusinessObject> .
  • I would like ISieve<ABusinessObject to execute a contract under which I could let someone call ForValues() and expect him to return ISieve with updated values.
  • However, at this point, EqualitySieve<ABusinessObject> is actually EqualitySieve<ABusinessObject, int> . But I don't really care about the type of properties at this point.
  • Essentially, since I am abstracting the EqualitySieve<ABusinessObject, int> , I also wanted to see if I can abstract this when accessing objects through the interface.
  • The long-term plan is that I want to have a SieveLocator where classes can implement IFindableSieve<ABusinessObject> , which would ideally return ISieve<ABusinessObject> . Then my goal would be to find these sieves for a given object.
  • So, I think that this is most likely a limitation of my design, and I have to find another way. Any suggestions on this or links to a template that I might not have seen would also be helpful.
+6
source share
2 answers

You can place general type parameters both on the interface and on the interface methods. Thus, the following example will define a common interface in which method F accepts one of them, "I don’t care what type it is, only that it is consistent."

 interface I<T> { //The generic type parameter U is independent of T. //Notice how F "forwards" the type U from input to output. Tuple<T, U> F<U>(U u); } 

Consider the following class of toys:

 class C : I<char> { public char Value { get; set; } public Tuple<char, U> F<U>(U u) { return Tuple.Create(Value, u); } } 

Here is a usage example:

 I<char> instance = new C { Value = '!' }; Tuple<char, int> x = instance.F(5); // ('!', 5) Tuple<char, string> y = instance.F("apple"); // ('!', "apple") 

Updates

  • I allow users to create EqualitySieve<ABusinessObject>().ForProperty(x=>x.AnInt) .
  • This actually returns EqualitySieve<ABusinessObject, int> user, but since this is a free interface, I remove them from having to take care of this part.
  • I would like EqualitySieve , LessThanSieve etc. implement ISieve<ABusinessObject> .

Using the ideas mentioned above, you can do what (I think) you need.

 interface ISieve<T> { //It still not clear what you actually want in this interface... } static class Sieve { public EqualitySieve<T> Equality<T>() { return new EqualitySieve<T>(); } public LessThanSieve<T> LessThan<T>() { ... } } class EqualitySieve<T> : ISieve<T> { //Notice how the property type P is independent of T //and can be inferred here from the passed expression public EqualitySieve<T, P> ForProperty<P>( Expression<Func<T, P>> propertyExpression) { return new EqualitySieve<T, P> { PropertyExpression = propertyExpression }; } } class EqualitySieve<T, P> : ISieve<T> { public Expression<Func<T, P>> PropertyExpression { get; set; } } 

Using:

 //Assuming MyObject.MyProperty is an int property //s has type EqualitySieve<MyObject, int> var s = Sieve.Equality<MyObject>().ForProperty(x => x.MyProperty); 
+3
source

There may be some tricks, so callers do not need to specify a type in the general method (think about how LINQ works), but unfortunately your research was correct, there is no way to deduce a type when composing a class that uses this type.

Closest you can get to it, having two levels of interfaces, where the outer layer does not use any functions that rely on the type TTypeIDontCareAbout .

 interface ISieve<TFilterObjectType,TTypeIDontCareAbout> : ISieve<TFilterObjectType> { TFilterObjectType ForValue(TTypeIDontCareAbout forValue); } interface ISieve<TFilterObjectType> { TFilterObjectType SomeOtherFunction(); } 

I do not know how to solve all your problems, but I think that Timothy's approach is what you want to use for two points.

  • I allow users to create EqualitySieve<ABusinessObject>().ForProperty(x=>x.AnInt) .
  • This actually returns EqualitySieve<ABusinessObject, int> user, but since this is a free interface, I remove them from having to take care of this part.
 interface ISieve<TFilterObjectType> { TFilterObjectType SomeOtherFunction(); EqualitySieve<TFilterObjectType, T> ForProperty<T>(Func<TFilterObjectType, T> selector); EqualitySieve<TFilterObjectType, T> ForProperty<T>(Expression<Func<TFilterObjectType, T>> selector); //This is how you would do it if you wanted IQueryable support. } 
+3
source

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


All Articles