简体   繁体   中英

Is there a way to find a collection in a class based on its type?

I am thinking of EF's DBContext and DBSets as the background to this question. You can access a particular set using the following code in a Repository class for example.

public TEntity Get(int id)
{
    return Context.Set<TEntity>().Find(id);
}

Where Set<TEntity>() returns the set of type TEntity . How exactly is this coded? I tried to find the source code for it to no avail. Would I need to create my own classes and write the logic out in full?

I'm guessing Enumerable.OfType<TResult>() will come in handy here. It returns an IEnumerable<TResult> over all the elements of type TResult in the source enumeration. As for its implementation, MSDN has this to say:

This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.

I don't know how EF does it, but you could easily accomplish something similar with a Dictionary keyed by Types

private Dictionary<Type, ICollection> registry = new Dictionary<Type, ICollection>();

// adds a collection of a certain type
public void Add<T>(T collection) where T: ICollection {
    registry.Add(typeof(T), collection);
}

// create an empty collection of type T and add it to registry
public void InitCollection<T>() where T: ICollection { 
    registry.Add(typeof(T), (ICollection)Activator.CreateInstance(typeof(T)));
}

// returns a collection of type T if it has been registered
public T Set<T>() where T: ICollection {
    return (T)registry[typeof(T)];
}

TLDR : EF creates just a DbSet<T> entry in a dictionary where the the key is typeof(T) .


Looking at the sourcecode it is implemented as following:

/// <summary>
///     Creates a <see cref="DbSet{TEntity}" /> that can be used to query and save instances of <typeparamref name="TEntity" />.
/// </summary>
/// <typeparam name="TEntity"> The type of entity for which a set should be returned. </typeparam>
/// <returns> A set for the given entity type. </returns>
public virtual DbSet<TEntity> Set<TEntity>()
    where TEntity : class
    => (DbSet<TEntity>)((IDbSetCache)this).GetOrAddSet(DbContextDependencies.SetSource, typeof(TEntity));

And Line 195 :

/// <summary>
///     This API supports the Entity Framework Core infrastructure and is not intended to be used
///     directly from your code. This API may change or be removed in future releases.
/// </summary>
object IDbSetCache.GetOrAddSet(IDbSetSource source, Type type)
{
    CheckDisposed();

    if (!_sets.TryGetValue(type, out var set))
    {
        set = source.Create(this, type);
        _sets[type] = set;
    }

    return set;
}

Where sets is :

private readonly IDictionary<Type, object> _sets = new Dictionary<Type, object>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM