开发者

C# Generics: Better Way to Match the Generic's Type to Another?

UPDATE: Didn't give a great ex开发者_高级运维ample. Hopefully it's better now.

Is there a better way than this:

(typeof(TRepository) == typeof(UserClass))

Here's the use in writing:

public static IBaseRepository<TClass> GetRepository<TClass>() where TClass : IDataEntity
{
  IBaseRepository<TClass> repository = null;

  if (typeof(TClass) == typeof(UserClass))
  {
     repository = (IBaseRepository<TClass>)new UserClassRepository();
  }

  if (typeof(TClass) == typeof(PostClass))
  {
     repository = (IBaseRepository<TClass>)new PostClassRepository();
  }

  return repository;
}

If something like this is run a lot, I hope there's better way than running typeof a bunch of times.


What you're doing here is a poor man's inversion of control container. Buckle up, learn the concepts of dependency injection and inversion of control and then you can write code like this:

IIoCContainer container = new IoCContainer();
container.RegisterType<IBaseRepository<UserClass>, UserClassRepository>();
container.RegisterType<IBaseRepository<PostClass>, PostClassRepository>();
var userClassRepository = container.Resolve<IBaseRepository<UserClass>>();

You can configure the container at runtime (as above) or in a configuration file. You can specify the object lifetime (transient, singleton, per thread, or custom). Dependency injection containers are intended to assist with object creation, especially for complex object structures and dependencies, coding to interfaces instead of concrete types (no more new ConcreteType()) and component configuration.

(By the way, drop the suffix Class from you class names (so User and Post, not UserClass and PostClass).)


the correct check would be:

if (typeof(TRepository).IsAssignableFrom(typeof(UserClass)))

additionally, if UserClassRepository is in fact derived from IBaseRepository, you don't need to cast it.

As an afterthought - why are you doing it this way? I'm sure there's a much better way to achieve what you want in a more repeatable manner.


You haven't really defined what you mean by "better." However, one way I might go about this is to create a custom attribute for each TClass that defines the repository, and read this attribute in your GetRepository method. It uses some Reflection, but it's more elegant than a big if-else, and more lightweight than a full-fledged dependency-injection framework. Quick example:

Attribute:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class RepositoryAttribute : Attribute
{
    public RepositoryAttribute(Type repositoryType)
    {
        this.RepositoryType = repositoryType;
    }

    public Type RepositoryType { get; private set; }
}

Entity class:

[Repository(typeof(UserClassRepository))]
public class UserClass
{
    // Class code
    // ...
}

Factory method:

public static IBaseRepository<TClass> GetRepository<TClass>()
  where TClass : IDataEntity
{
    Type t = typeof(TClass);
    RepositoryAttribute attr =
        (RepositoryAttribute)Attribute.GetCustomAttribute(t,
          typeof(RepositoryAttribute), false);
    if (attr != null)
    {
        return (IBaseRepository<TClass>)Activator.CreateInstance(attr.RepositoryType);
    }
    return null;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜