C # Tạo T mới ()


158

Bạn có thể thấy những gì tôi đang cố gắng (nhưng không thành công) để làm với đoạn mã sau:

protected T GetObject()
{
    return new T();
}

Mọi sự trợ giúp sẽ rất được trân trọng.

BIÊN TẬP:

Bối cảnh như sau. Tôi đã chơi xung quanh với một lớp trình điều khiển tùy chỉnh cho tất cả các bộ điều khiển xuất phát từ, với các phương thức được tiêu chuẩn hóa. Vì vậy, trong bối cảnh, tôi cần tạo một thể hiện mới của đối tượng của kiểu điều khiển. Vì vậy, tại thời điểm viết, nó là một cái gì đó như:

public class GenericController<T> : Controller
{
    ...

    protected T GetObject()
    {
        return (T)Activator.CreateInstance(ObjectType);
    }        

    public ActionResult Create()
    {
        var obj = GetObject()

        return View(obj);
    }

Và vì vậy tôi quyết định phản ánh là dễ nhất ở đây. Tôi đồng ý rằng, chắc chắn đưa ra tuyên bố ban đầu của câu hỏi, câu trả lời thích hợp nhất để đánh dấu là chính xác là câu hỏi sử dụng ràng buộc mới (). Tôi đã sửa nó lên.


27
Không, tôi không thấy những gì bạn đang cố gắng và không làm. Tôi thấy một đoạn mã có thể là một phần của chương trình làm việc, không có ngữ cảnh, không có thông báo lỗi và không có lời giải thích.
Ben Voigt

17
Aw, tôi ghét nó khi câu trả lời sai được chọn!
David Heffernan

Câu trả lời:


409

Hãy nhìn vào ràng buộc mới

public class MyClass<T> where T : new()
{
    protected T GetObject()
    {
        return new T();
    }
}

Tcó thể là một lớp không có hàm tạo mặc định: trong trường hợp này new T()sẽ là một câu lệnh không hợp lệ. Các new()ràng buộc nói rằng Tphải có một hàm tạo mặc định, làm cho new T()hợp pháp.

Bạn có thể áp dụng cùng một ràng buộc cho một phương thức chung:

public static T GetObject<T>() where T : new()
{
    return new T();
}

Nếu bạn cần truyền tham số:

protected T GetObject(params object[] args)
{
    return (T)Activator.CreateInstance(typeof(T), args);
}

2
Cảm ơn, bạn đời - tôi rất vui vì đã học được điều này ngày hôm nay. Với bối cảnh của phương pháp của tôi, tôi đã đi đến giải pháp phản ánh. Chúc mừng!
Hanshan

8
@nulliusinverba - hmm ... sẽ thật tuyệt nếu bạn chỉ ra bối cảnh của phương pháp của bạn trong câu hỏi.
Alex Aza

1
@nulliusinverba - bạn đã không hiển thị trong câu hỏi rằng bạn cần tham số.
Alex Aza

1
@Alex - Khi tôi đọc câu hỏi của anh ấy, tôi cho rằng anh ấy không muốn tham số: Tuy nhiên, hãy bình chọn cho bạn :)
Phill

Có thể sử dụng một cái gì đó như ràng buộc (tham số) mới?
Louis Rhys


29

Một cách khác là sử dụng sự phản chiếu:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}

Cảm ơn, bạn đời - Tôi đã đi với giải pháp này với bối cảnh của phương pháp.
Hanshan

22
Cũng giống như một FYI, điều này có thể được viết thay thế là Activator.CreateInstance (typeof (T), chữ ký, args); xem msdn.microsoft.com/en-us/l Library / 4b0ww1we.aspx để biết thêm chi tiết.
Chris Baxter

@ Bộ mã hóa: Việc sử dụng cho chữ ký loại [] là gì, bạn chỉ có thể gọi trực tiếp CreatInstance với các thông số, mà không chỉ định rõ ràng chữ ký. Trong cả hai trường hợp, bạn sẽ nhận được MissingMethodException nếu không có hàm tạo phù hợp.
Boris B.

4
Ngay cả khi đây là câu trả lời phù hợp nhất với bạn, rõ ràng đây không phải là câu trả lời tốt nhất cho cộng đồng. Những người tìm kiếm câu hỏi này đang tìm kiếm câu trả lời từ bên dưới, thực sự.
Bẫy

Và chính xác bối cảnh đó là gì? Vui lòng thêm nó vào câu hỏi ban đầu.
James

18

Chỉ cần hoàn thành, giải pháp tốt nhất ở đây thường là yêu cầu đối số chức năng của nhà máy:

T GetObject<T>(Func<T> factory)
{  return factory(); }

và gọi nó là một cái gì đó như thế này:

string s = GetObject(() => "result");

Bạn có thể sử dụng điều đó để yêu cầu hoặc sử dụng các tham số có sẵn, nếu cần.


16

Các ràng buộc mới là tốt, nhưng nếu bạn cần T là một loại giá trị quá, sử dụng này:

protected T GetObject() {
    if (typeof(T).IsValueType || typeof(T) == typeof(string)) {
        return default(T);
    } else {
       return (T)Activator.CreateInstance(typeof(T));
    }
}

7

Vì cái này được gắn thẻ C # 4. Với khung công tác mở ImpromptuIntereface, nó sẽ sử dụng dlr để gọi hàm tạo, nó nhanh hơn đáng kể so với Activator khi hàm tạo của bạn có đối số và chậm hơn đáng kể khi không có. Tuy nhiên, ưu điểm chính là nó sẽ xử lý các hàm tạo với các tham số tùy chọn C # 4.0 một cách chính xác, điều mà Activator sẽ không làm.

protected T GetObject(params object[] args)
{
    return (T)Impromptu.InvokeConstructor(typeof(T), args);
}

4

Để có được điều này tôi đã thử đoạn mã sau:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.