简体   繁体   中英

Func delegate to declared method

Having these two methods declared in a non-generic class, which share the same signature:

    private TypeResolverResult<T> TryRetrieveFromReusable<T>(TypeResolverConfiguration<T> typeResolverConfiguration) where T : class 
    {
        return null;
    }

    private TypeResolverResult<T> BuildNew<T>(TypeResolverConfiguration<T> typeResolverConfiguration) where T : class
    {
        return null;
    }

How can I create a delegate that represents these methods' signature?

I can't seem to get it, I tried:

    private Func<TypeResolverConfiguration<T>, TypeResolverResult<T>> _typeResolveFunc;

But obvious this does not work because the class is non-generic and I can't change that.

Thanks

UPDATE

This is more or less what I need:

    public class Manager : ATypeResolver, IManager
    {
        private neeedDelegate;


        public Manager(RuntimeConfiguration runtimeConfiguration, IList<RepositoryContainer> repositories)
        {
            if (runtimeConfiguration.WhatEver)
            {
                neeedDelegate = TryRetrieveFromReusable;
            }
            else
            {
                neeedDelegate = BuildNew;
            }
        }

        public override TypeResolverResult<T> Resolve<T>() where T : class
        {
            //Want to avoid doing this:

            if (runtimeConfiguration.WhatEver)
            {
                TryRetrieveFromReusable(new TypeResolverConfiguration<T>());
            }
            else
            {
                BuildNew(new TypeResolverConfiguration<T>());
            }

            //and have just this

            neeedDelegate<T>(new TypeResolverConfiguration<T>());
        }

        private TypeResolverResult<T> TryRetrieveFromReusable<T>(TypeResolverConfiguration<T> typeResolverConfiguration) where T : class 
        {
            return null;
        }

        private TypeResolverResult<T> BuildNew<T>(TypeResolverConfiguration<T> typeResolverConfiguration) where T : class
        {
            return null;
        }
    }

Update From what I can see, an approach like this should work, as long as ATypeResolver has a where T : class on Resolve<T> :

public class Manager : ATypeResolver, IManager
{
    private bool tryRetrieveFromReusable;

    public Manager(RuntimeConfiguration runtimeConfiguration, IList<RepositoryContainer> repositories)
    {
        this.tryRetrieveFromReusable = runtimeConfiguration.WhatEver;
    }
    public override TypeResolverResult<T> Resolve<T>()
    {
        var typeResolver = tryRetrieveFromReusable ? (TypeResolver<T>)TryRetrieveFromReusable : BuildNew;

        return typeResolver(new TypeResolverConfiguration<T>());
    }
}

This uses a custom delegate type (a Func like you have should work too):

public delegate TypeResolverResult<T> TypeResolver<T>(
    TypeResolverConfiguration<T> typeResolverConfiguration) where T : class;

If you like, you can move the var typeResolver = ... line to its own method, to separate the logic and allow you to use it from more than just Resolve . If you did that, Resolve might be as simple as: return GetTypeResolver<T>()(new TypeResolverConfiguration<T>()); .

You seem to not understand exactly how generics work. I'll give a quick overview, but read the MSDN .

When you have a generic class

public class Foo<T>
{
    public T Bar {get; set;}
}

And you use it something like this

Foo<int> intFoo = new Foo<int>();
Foo<string> stringFoo = new Foo<string();

At compile time, the compiler will detect the two usages of the generic type. It will create a type of each usage. So your assembly will have types that look something like this (no not exactly, but let's play pretend so that we humans can understand).

public class FooInt
{
    public int Bar { get; set; }
}

public class FooString
{
    public string Bar { get; set; }
}

And it will replace all uses of Foo<int> with FooInt and Foo<string> with FooString

Now if we have a non-generic class with a generic method

public class Foo
{
    public T GetBar<T>() { ..... }
}

And you use it like this

Foo foo = new Foo();
int x = foo.GetBar<int>();
string s = foo.GetBar<string();

The compiler will generate

public class Foo
{
    public int GetBarInt() { ..... }
    public string GetBarString() { ..... }
}

And it will replace GetBar<T> with GetBarInt and GetBar<string> with GetBarString

But fields aren't like that. If you have a class that looks like so

public class Foo
{
    public T Bar;
}

You cannot do this

Foo foo = new Foo();
foo.Bar<int> = 1;
foo.Bar<string> = "test";

The compiler just doesn't understand that. I'm not an expert on the internals, but my guess is that because this points to a place in memory, the compile cannot generate the generic usages at compile time.

But the point I am trying to make is this. Generics are not some magical "I don't need to specify the type" feature. They are hints to the compile that say "I am going to do this same thing multiple times, I want you to generate the code for me."

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