Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional Generic Types [closed]

Tags:

c#

generics

Is there a better way to write this? As one class perhaps, instead of two.

using System;

namespace SnippetTool.Repositories
{
    public abstract class ARepository<TProvider> where TProvider : class
    {
        protected TProvider Provider { get; set; }

        protected ARepository(TProvider provider)
        {
            if (provider == null)
                throw new ArgumentNullException("provider");

            Provider = provider;
        }
    }

    public abstract class ARepository<TProvider, TValidator> : ARepository<TProvider> where TProvider : class where TValidator : class
    {
        protected TValidator Validator { get; set; }

        protected ARepository(TProvider provider, TValidator validator) : base(provider)
        {
            Validator = validator;
        }
    }
}
like image 802
CaffGeek Avatar asked Aug 16 '12 20:08

CaffGeek


People also ask

What is an open generic type?

An open generic type is simply a generic type whose type parameters have not been specified. For example, IEnumerable<> is an open generic type, and IEnumerable (or string or whatever) is a **closed generic type**, as its type parameter has been specified.

How do I make my optional generic typescript?

To make a generic type optional, you have to assign the void as the default value. In the example below, even though the function takes a generic type T, still you can call this function without passing the generic type and it takes void as default.

What is generic type?

Definition: “A generic type is a generic class or interface that is parameterized over types.” Essentially, generic types allow you to write a general, generic class (or method) that works with different types, allowing for code re-use.

How do I restrict a generic type in Java?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class.


1 Answers

I don't think you can do it as one class, currently, generally what I try to do in this situation is create the most general class (the one that takes the most generic args) to have all the logic, then make the more specific ones be subclasses that default those types.

For example, let's say we are writing a translator that translates from one type of value to another, so like a Dictionary but also has defaults, etc.

We could define this as:

public class Translator<TKey, TValue, TDictionary> where TDictionary : IDictionary<TKey, TValue>, new();
{
    private IDictionary<TKey, TValue> _map = new TDictionary();
    ...
}

This is my generic case, which can have any implementation of IDictionary, but say we want a simpler version that always uses Dictionary if not specified, we could do:

public class Translator<TKey, TValue> : Translator<TKey, TValue, Dictionary<TKey, TValue>>
{
    // all this does is pass on the "default" for TDictionary...
}

In this way, I can make:

// uses Dictionary<int, string>
var generic = new Translator<int, string>(); 

// uses SortedDictionary instead
var specific = new Translator<int, string, SortedDictioanry<int, string>>();

So in your case, maybe your generic always has a TValidator property, but it's defaulted (maybe to always return true in your most generic form?

For example, maybe you have a definition of a default validator (say called DefaultValidator) you could reverse your definitions so that the more generic (the one that takes more generic type parameters) has all the logic and any specializations (fewer type parameters) are just subclasses that default those extra types:

using System;

namespace SnippetTool.Repositories
{
    public class DefaultValidator
    {
       // whatever your "default" validation is, may just return true...
    }

    public abstract class ARepository<TProvider> : ARepository<TProvider, DefaultValidator>
        where TProvider : class
    {
        protected ARepository(TProvider provider) : base(provider, new DefaultValidator());
        {
        }

        // needs no new logic, just any specialized constructors...
    }

    public abstract class ARepository<TProvider, TValidator> 
         where TProvider : class 
         where TValidator : class
    {
        public TValidator Validator { get; set; }

        protected ARepository(TProvider provider, TValidator validator) 
        {
            Provider = provider;
            Validator = validator;
        }

        // all the logic goes here...
    }
}

UPDATE: Yes, based on your comment, if the TValidator is an add-on (and not something defaulted), then layering it like you did is appropriate.

like image 195
James Michael Hare Avatar answered Oct 25 '22 23:10

James Michael Hare