简体   繁体   中英

Automatically creating type of method

How can I automatically initialize the type of a method in C#?

For instance,

List<int> MyIntList()
{
    List<int> returnList = new List<int>();
    return returnList;
}

I've basically created an instance of the return type, to return. Is there something in the C# language that infers the type to return, so that an instance doesn't have to be created within the method, such as:

List<int> MyIntList()
{
    // invalid - "this" refers to the containing class,
    // but looking for something that refers to the containing method.
    this = new List<int>();
    return this;
}

Simply put, can I prevent List<int> in the example from being typed more than once, and let the compiler infer the rest?

If I understand you correctly you mean something like this:

List<int> MyIntList()
{
    var result = new List<int>();
    return result;
}

var is just a placeholder for the actual type List<int> or whatever you assign to it. In contrast to JavaScript in C# the keyword relate to a strong type so you can deal with it as with any other type, it automatically lists the correct members appropriate for that type.

EDIT: To answer why you can´t do what you want: The method-signature often states that an interface is returned, however the actual type doesn´t matter at all. Usually you won´t care if the method actually returns a List , a Dictionary or anything else as long as it implements IEnumerable for example. However if you´d force the compiler to return a List<int> instead of an IEnumerable<int> for example you lose all the benfits of interfaces as you allways infer the actual type insteaf of the interface. Having said this the consumer of the mthod could even add or remove elements from/to the list being returned. If you´d use the mentioned interface all you return is something that represents a list of values which can be enumerated.

Also consider this case:

List<int> MyIntList()
{
    if (anyCondition)
    {
        var result = new List<int>();
        return result;
    }
    else 
    {
        var result = new int[0];
        return result
    }
}

What type should the compiler infer in this case? The signature of the method is a contract to the outside which determines which things you can do with the result.

Perhaps this:

private static T GetSomething<T>() where T: new()
{
    return new T();
}

But then you will need to pass the type as typeparameter T :

var x = GetSomething<List<int>>();

You're looking for something like

auto MyIntList()
{
    return new List<int>();
}

Having the compiler infer the return value and replace auto with List<int>

This is not possible with the latest version of C# (6.0)

I can't give a precise answer as to whether the C# specification disallows it, but I can provide examples. First, what if you want a method to return an interface? In your examples you used List<int> but what if you changed it to IList<int> ? Or consider this simplified example:

public interface IFoo
{
    void Bar();
}
public class Foo1 : IFoo
{
    public Foo1() { }
    public void Bar() => Console.WriteLine("Foo1.Bar");
}
public class Foo2 : IFoo
{
    private Foo2() { }
    public static Foo2 Create => new Foo2();
    public void Bar() => Console.WriteLine("Foo2.Bar");
}

You cannot create an instance of an interface. So this is wrong:

public IFoo BadFooCreate() => new IFoo(); // won't compile

But this would work, though it begs the question of how the compiler know you want Foo1 to be the particular IFoo that is returned:

public IFoo GoodFooCreate() => new Foo1(); // compiles okay

This works too:

public IFoo GoodFooCreate() => Foo2.Create(); // compiles okay

But since Foo2 has a private constructor, this would not work:

public IFoo BadFoo2Create() => new Foo2(); // won't compile

Another set of examples revolve around abstract classes. Consider:

public abstract class Animal
{
    public Animal() { }
    public virtual string Name => "Generic Animal";
    public abstract string Speak();
}
public class Dog : Animal
{
    public override string Name => "Dog";
    public override string Speak() => "Bark";
}
public class Cat : Animal
{
    public override string Name => "Cat";
    public override string Speak() => "Meow";
}

This would be wrong because you can't create an instance of an abstract class:

public Animal BadAnimalCreate() => new Animal(); // won't compile

But this works perfectly fine:

public Animal GoodAnimalCreate() => new Dog(); // compiles okay

Although again if the compiler were to automatically create a type for a lazy programmer, how would the compiler know to use Dog() and not Cat()? Letting the compiler pick on your behalf encroaches on violating the Principle of Least Astonishment . There's being lazy and then there's abdicating your responsibility.

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