You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#泛型问题:抽象方法中如何确定使用对应派生类

Solution & Analysis for Your C# Generic File Processor Issue

Let's tackle this problem step by step, starting with fixing the error and then optimizing to reduce duplicate code, followed by addressing your question about generic best practices.

First: Fix the "Type must be a reference type" Error

The root issue is mismatched generic constraints. Your third-party doProcess<T>() requires T to be a reference type (class) with a parameterless constructor (new()), but your getValuesFromFile<T>() only enforces T : FileType.

To resolve this, merge the required constraints into your base class method. Make sure all your FileType implementations (like FileType1, FileType2) are reference types (which they already are, since they're classes) and have a parameterless constructor (add one if they don't—this is mandatory for the third-party library):

abstract class FileProcessor { 
    protected List<T> getValuesFromFile<T>() 
        where T : FileType, class, new() { // Combine all required constraints
        try { 
            return otherClass.doProcess<T>();
        } catch (Exception ex) { 
            throw new Exception("Unable to retrieve the data from the file.", ex); 
        } 
    } 
}

Note: Constraint order matters here—base class/interface constraints come first, then class/struct, then new().

Second: Minimize Duplicate Code in Derived Processors

To avoid repeating generic method calls in every derived processor, you have two clean options:

Option 1: Make FileProcessor a Generic Base Class

Bind the base class directly to a specific FileType so derived classes don't need to redefine the generic logic:

// Generic base class with all shared logic
abstract class FileProcessor<T> 
    where T : FileType, class, new() { 
    protected List<T> GetValuesFromFile() { 
        try { 
            return otherClass.doProcess<T>(); 
        } catch (Exception ex) { 
            throw new Exception("Unable to retrieve the data from the file.", ex); 
        } 
    } 
}

// Derived classes are now clean and type-bound
class Processor_FileType1 : FileProcessor<FileType1> {} 
class Processor_FileType2 : FileProcessor<FileType2> {}

This is the most concise approach—each processor automatically inherits the correct type-specific logic without any redundant code.

Option 2: Keep Non-Generic Base Class, Add Simple Wrappers

If you need a non-generic base class (e.g., for grouping processors in a non-generic collection), add type-specific wrapper methods in derived classes that call the shared generic base method:

abstract class FileProcessor { 
    protected List<T> getValuesFromFile<T>() 
        where T : FileType, class, new() { 
        try { 
            return otherClass.doProcess<T>(); 
        } catch (Exception ex) { 
            throw new Exception("Unable to retrieve the data from the file.", ex); 
        } 
    }
}

class Processor_FileType1 : FileProcessor { 
    public List<FileType1> GetValues() {
        return getValuesFromFile<FileType1>();
    }
}

class Processor_FileType2 : FileProcessor { 
    public List<FileType2> GetValues() {
        return getValuesFromFile<FileType2>();
    }
}

This still centralizes all error handling and third-party calls in the base class, leaving derived classes with minimal boilerplate.

Is This Bad Generic Programming?

No—this is actually a great use of generics!

Your setup leverages generics to:

  1. Enforce type safety: Each processor is tied to exactly one FileType, preventing mismatched file-data pairs.
  2. Reduce code duplication: Shared logic (error handling, third-party calls) lives in the base class instead of being copied across every processor.
  3. Maintain flexibility: If you add a new FileType3, you only need to create a Processor_FileType3 class—no need to rewrite the data retrieval logic.

The only caveat is ensuring all FileType implementations meet the class, new() constraints required by the third-party library. As long as you control those classes (which you do, per your code), this is a solid, maintainable design.

内容的提问来源于stack exchange,提问作者John Bustos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:43:02