通用代表C#

Eve*_*lie 4 c# generics delegates

我试图弄清楚如何使泛型委托返回一个通用值.我的第一个非泛型场景看起来像这样.

    delegate int FirstDelegate(int i);
    static FirstDelegate method;

    static void Main(string[] args)
    {
        method = ReturnInt;
        int i = method(3);
    }

    static int ReturnInt(int i)
    {
        return i;
    }
Run Code Online (Sandbox Code Playgroud)

这里没问题.一切正常.然而,当我把它变成通用时,事情就会失去控制.

    delegate T FirstDelegate<T>(T i);
    static FirstDelegate<T> method; <--
Run Code Online (Sandbox Code Playgroud)

他已经在这里开始抱怨找不到类型或名称空间等.任何人都有任何关于如何使这个工作的想法?

编辑:我的真正目标是我有一个可以包含许多不同缓存对象的缓存.现在我想要一个通用的方法,这样我就可以通过这个方法得到所有对象.我可以让它返回对象或基类,但是我仍然必须在每个对象的任何地方使用它.

狗/猫的例子非通用的部分正在工作..通用..不是那么多

class Program
{
    static void Main(string[] args)
    {
        //Clientside
        Cache.method = GetAnimalOnClient;

        //not working
        Cache.methodGeneric = GetAnimalOnClientGeneric;

        var cat = Cache.GetCachedObj(AnimalType.Cat);
        var dog = Cache.GetCachedObj(AnimalType.Dog);

        //Want do
        vad dog = Cache.GetCachedObj<Dog>();
    }

    private static Animal GetAnimalOnClient(AnimalType type)
    {
        if (type == AnimalType.Dog)
            return Cache._Dogs.First();
        else
            return Cache._Cats.First();
    }

    /// <summary>
    /// This is the one I want to use
    /// </summary>
    private static T GetAnimalOnClientGeneric<T>() where T: Animal
    {
        if (typeof(T) == typeof(Cat))
            return Cache._Cats.First() as T;
        return Cache._Dogs.First() as T;
    }
}

public enum AnimalType
{
    Dog,
    Cat
}

public static class Cache
{
    delegate Animal GetCacheObjectDelegate(AnimalType type);
    public static GetCacheObjectDelegate method;

    delegate Animal GetCacheObjectDelegate<T>() where T : Animal;
    public static GetCacheObjectDelegate<T> methodGeneric; //<--Complains here

    public static List<Dog> _Dogs = new List<Dog>();
    public static List<Cat> _Cats = new List<Cat>();

    public static Animal GetCachedObj(AnimalType type)
    {
        return method(type);
    }

    public static T GetCachedObj<T>() where T: Animal
    {
        return methodGeneric<T>(); //NOPE
    }
}

public class Animal
{

}

public class Dog : Animal
{

}

public class Cat : Animal
{

}
Run Code Online (Sandbox Code Playgroud)

dca*_*tro 6

你的事情太复杂了.

public static class Cache
{
    private static List<Dog> _dogs = new List<Dog>();
    private static List<Cat> _cats = new List<Cat>();

    public static TAnimal GetCachedObj<TAnimal>() where T: Animal
    {
        if(TAnimal == typeof(Dog))
           return (TAnimal) _dogs.First();
        else if (TAnimal == typeof(Cat))
           return (TAnimal) _cats.First();
        else throw new InvalidOperationException("Invalid generic type argument");
    }
}
Run Code Online (Sandbox Code Playgroud)

但是你的整个设计有一个缺陷:它打破了Liskov替代原则.

LSP声明如果T(例如Cat)是子类型Animal,则可以替换任何实例而没有任何令人惊讶的效果.AnimalT

让我说清楚.假设你决定创造一种新动物,a Giraffe.现在,如果你打电话GetCachedObj<Giraffe>,你会得到一个例外!代码中并没有对工作的任何亚型Animal,该LSP不成立!

相反,您应该使缓存类通用,并为每种动物使用缓存实例

public class Cache<T> where T: Animal
{
    private static List<T> _animals = new List<T>();

    public T GetCachedObj()
    {
        return _animals.First();
    }
}

var dogsCache = new Cache<Dog>();
Dog dog = dogsCache.GetCachedObj();

var catsCache = new Cache<Cat>();
Cat cat = catsCache.GetCachedObj();
Run Code Online (Sandbox Code Playgroud)

这将永远适用于任何种类的动物.

注意:我认为Cache不应该是静态的.相反,您可以使用Singleton模式在应用程序中创建一个缓存实例(每种动物类型),或使用依赖注入(使用Castle Windsor等框架)将缓存注入每个客户端.


老答案

您可以在声明时将方法的泛型类型参数绑定到特定类型(如提到的@Sean),也可以将封闭类型设置为泛型.

public class MyClass<T>
{
    public FirstDelegate<T> Method(){...}
}
Run Code Online (Sandbox Code Playgroud)

您也可以保留T未绑定(不使封闭类型通用),但您必须在方法名称T 声明,如下所示:

public FirstDelegate<T> Method<T>(){...}
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,在某个时间点,T都将绑定到特定类型.在这种情况下,T将在创建MyClass(即new MyClass<int>)的实例时绑定,就像使用a一样List<T>.