I'm trying to use generics in inheritance with structs, see.
public class AuditLogEntry : ObjectBase<AuditLogEntry.AuditLogEntryStruct>
{
private struct AuditLogEntryStruct
{
public int AuditID;
}
}
public abstract class ObjectBase<T>
{
}
It won't let me use private for my struct, as it throws the error:
Inconsistent accessibility: base class 'ObjectBaseAuditLogEntry.AuditLogEntryStruct>' is less accessible than class 'AuditLogEntry'.
However I don't really want to make my struct public.
Any ideas?
Thanks,
Alex
Follow on question:
Here is what we are trying to do:
class AuditLogEntry : ObjectBase<AuditLogEntry.AuditLogEntryStruct>
{
internal struct AuditLogEntryStruct
{
public int AuditID;
}
public int AuditID
{
get
{
return udtObject.AuditID;
}
set{
BeginEdit();
udtObject.AuditID = value;
}
}
class ObjectBase<T>
{
protected T udtObject;
protected T udtPreEditObject;
protected void BeginEdit()
{
if (!IsDirty)
{
IsDirty = true;
udtPreEditObject = udtObject;
}
}
}
I'm not sure how to achive this within making AuditLogEntryStruct public?
Thanks,
Alex
You can't derive a public class from a generic class when one or more of the type arguments aren't public
The types that any type derives from has to be as accessible as the deriving class, inculding any type parameters given as type arguments to the base class
if you have
public class publicClass{}
Any class can derive from A however if you changed it to
internal class internalClass{}
only other internal classes can derive from it.
The same is true if you passed either of the types as a type parameter. The first three below are valid the fourth is not
public class A : List<publicClass>{}
internal class B : List<internalClass>{}
internal class C : List<publicClass>{}
//not valid because D has wider accessibility than the close generic type List<internalClass>
public class D : List<internalClass>{}
EDIT
The language team at some point have had to make a decision whether to make a declaration as yours invalid or make any use of your type that resulted in illegal access to an inaccessible type invalid. In your case there would be several methods returning a type that would be inaccessible to all others than your class and a number of methods taking an argument of a type no other class could provide. So the only objects that would actually be able to use objects of your class would be objects of your class. You can solve that with composition instead of inheritance
public class AuditLogEntry
{
private ObjectBase<AuditLogEntry.AuditLogEntryStruct> _entry;
private struct AuditLogEntryStruct
{
public int AuditID;
}
}
public abstract class ObjectBase<T>
{
}
Consider this example:
public class Foo : List<Bar>
{
private struct Bar { }
}
var myFoo = new Foo();
...
var x = myFoo()[0]; // expression on the right side is of type Bar, yet Bar is inaccessible
UPDATE
What you are trying to achieve doesn't really require generics. You only access your structs inside ObjectBase<T> as if they were objects. You might as well change them to object and remove generic type altogether.
If you have some more logic that requires some sort of functionality from AuditLogEntryStruct to be accessable in ObjectBase<T>, you may extract an interface:
public interface IStructsWithSomeFunctionality { ... }
make your struct implement it and use it as your type parameter
public class AuditLogEntry : ObjectBase<IStructsWithSomeFunctionality> { ... }
Related
I have two abstract classes that can be inherited for explicit usage: A_GUI_Info and A_Info_Data. The GUI_Infos are GUI elements that display data. The Info_Datas are data classes, that transfer specific data to the according GUI_Info.
I want to express the dependency that an explicit GUI_Info has one explicit Info_Data through generics and still allow an inheritance. With other words, I want to avoid that a wrong explicit Info_Data is fed to an explicit GUI_Info. For example, I feed HUD_Info_Data to a Wrist_GUI_Element that does not have the means to represent it. > A kind of type-safety for inherited generics
Example:
class HUDInfoData : A_Info_Data
class HUDInfo<HUDInfoData > : A_GUI_Info<A_Info_Data>
// but the generic cant be inherited like that
class HUDInfo : A_GUI_Info<A_Info_Data>
// doesnt define dependency
class HUDInfo : A_GUI_Info<HUDInfoData >
// also not working
Another approach is restrictions by where T : A_GUI_Info<D> where D : A_Info_Data But it did not work like that.
The final requirement, that I cant get to work is: I have an instance of the explicit Info and want to handle it in a function, that could also handle all other inherited Infos with their according Datas.
public HUD_Info<HUD_Info_Data> obj;
public List<A_GUI_Info<A_Info_Data>> infos;
public void SetConnection(string ID, A_GUI_Info<A_Info_Data> p)
{
infos.Add(p);
}
It may end up that you need to use this kind of data structure:
public abstract class A_GUI_Info<G, D>
where G : A_Info_Data<G, D>
where D : A_GUI_Info<G, D>
{
public G Gui { get; set; }
}
public abstract class A_Info_Data<G, D>
where G : A_Info_Data<G, D>
where D : A_GUI_Info<G, D>
{
public D Data { get; set; }
}
It's not overly nice, but it does tie the two derived types to each other.
You would defined them like this:
public class HUDInfoData : A_Info_Data<HUDInfoData, HUDInfo>
{
}
public class HUDInfo : A_GUI_Info<HUDInfoData, HUDInfo>
{
}
Have you tried:
abstract class A_Info_Data { ... }
abstract class A_GUI_Info<T> where T: A_Info_Data { ... }
And now:
class CriticalData: A_Info_Data { ... }
class CriticalGui: A_GUI_Info<CriticalData> { ... }
The type parameter on the base class only exists on the base class. The more derived class has to define a new type parameter and pipe through the type to the base class's type parameter. This gives you a place to pose more generic constraints.
For example:
class HUDInfo<THudInfoData> : A_GUI_Info<THudInfoData> where THudInfoData : A_Info_Data
Now, HUDInfo<> can take any HudInfoData as long as it derives from A_Info_Data (or if it is A_Info_Data). If you wanted to have HUDExtremelySpecificInfo which could only take HUDExtremelySpecificInfoData, that would look like:
class HUDExtremelySpecificInfo<THudInfoData> : A_GUI_Info<THudInfoData>
where THudInfoData : HUDExtremelySpecificInfoData
If you never want to specify the type because you know that it will always be HUDExtremelySpecificInfoData, you can also declare either both:
class HUDExtremelySpecificInfo<THudInfoData> : A_GUI_Info<THudInfoData>
where THudInfoData : HUDExtremelySpecificInfoData { .. }
class HUDExtremelySpecificInfo : HUDExtremelySpecificInfo<HUDExtremelySpecificInfoData> { .. }
(where you implement the non-generic HUDExtremelySpecificInfo in terms of the generic HUDExtremelySpecificInfo<>, and can use the generic one if there's a specific even more extremely specific info data subclass that you want to specify)
or just one:
class HUDExtremelySpecificInfo : A_GUI_Info<HUDExtremelySpecificInfoData> { .. }
Thank you all for giving constructive answers. What I try here is not working like preferred (pbbly not possible at all). This is what I came up with:
// abstract definitions
public abstract class AInfo
{
public abstract void SetData(AInfoData data);
}
public abstract class AInfoData
// explicit definitions
public class WristInfo : AInfo
{
public override void SetData(AInfoData data)
{
Data_Info_Wrist d = (Data_Info_Wrist)data; // cast to use
}
}
public class Data_Info_Wrist : AInfoData
// runtime usage
public AInfo instance; (WristInfo)
public void Setup(AInfo info) { }
For Unity workflow I require the explicit class to be non-generic. So this workaround is possibly the best solution. The drawback: The desired type-safety is not given here.
I want to subclass a large number of classes so that they will all contain a certain set of the same properties. What would be the right way to do it in order to avoid repetition? I thought of using generics like:
public class SuperT<T> : T
{
//the same set of properties
}
But the compiler says
Cannot derive from 'T' because it is a type parameter
EDIT: I am trying to subclass some classes in a third party assembly so I cannot use a base class.
For example, the types are "Image", "Label", "Button" etc and I want to subclass them all to contain a property like "Radius". (So that I would use SuperImage element in XAML and when I set it's Radius property from XAML, I will be able to run some certain logic.)
One other way I just thought of right now is using T4 templates. I wonder if there is a way to do this with generics without resorting to templates? I cannot understand why the compiler rejects it.
If these classes all share a common base class or common interface you could write an extension method.
public static class ShapeExetnsionsExtLib
{
public static double Radius(this ShapeBase shape){
return /*calculate radious*/;
}
}
From comments
I am trying to subclass some classes in a third party assembly so I cannot use a base class.
For example, the the types are "Image", "Label", "Button" etc and I want to subclass them all to contain a property like "radius".
Yes they share common base classes but I cannot add anything new to them.
I don't think generics have anything to do with this, however inheritance is probably what you're looking for.
There are two types of inheritance that you can use to subclass, and extension methods work to "superclass"... sort of.
Is-A inheritance
Has-A inheritance
And to simply add a similar method to a bunch of third party objects, you'll use an extension method.
Is-A inheritance
Use a base class if you've got similar method implementations.
public abstract class BaseFoo {
public void Bar() {
// actual code
}
}
public class Foo : BaseFoo
{
}
var foo = new Foo();
foo.Bar();
Use an Interface if you need to implement the same method on each class.
public interface IFoo {
void Bar();
}
public class Foo : IFoo {
public override void Bar(){
// bar implementation
}
}
var foo = new Foo();
foo.Bar();
Combining the two is also allowed, but you can only inherit on base class, where you can inherit multiple interfaces.
Has-A inheritance
This is particularly useful with dependency injection, but it's simply the notion that you have an instance of another class to work with. It's essentially a wrapper class for you to work with.
public class Foo {
private readonly ThirdPartyFoo _tpFoo;
void Foo(ThirdPartyFoo tpFoo) {
_tpFoo = tpFoo;
}
public void Bar(){
// now I can do something with _tpFoo;
_tpFoo.Bar();
}
}
var tpFoo = new ThirdPartyFoo();
var foo = new Foo(tpFoo);
foo.Bar(); // invokes the underlying tpFoo
Lastly, if you just need to add a method to existing classes, then you create an extension method.
public static class ViewExtensions()
{
// this assumes your Image, Button, Label all inherit from View.
public static Whatever Radius(this View view) {
// do your radius work.
}
}
Just Use a base class:
public class Base
{
public int Id { get; set; }
public string Name { get; set; }
}
And inherite from it:
public class A : Base
{
}
public class B : Base
{
}
In general, you want to use one of the answers already posted about using a base class and inheriting from that. However, if the classes are in a third party library and are marked as sealed, then you will need to create a wrapper class to use as a base class.
(Note that this option is a workaround and doesn't truly inherit from the third party class, so things in that class that are marked as protected won't be accessible without a liberal use of reflection.)
// The sealed class within another library
public sealed ThirdPartyClass
{
public ThirdPartyClass(int i) { }
public int SomeProperty { get; set; }
public int SomeMethod(string val) { return 0; }
public static void SomeStaticMethod() { }
}
// The wrapper class to use as a pseudo base class for ThirdPartyClass
public class BaseClass
{
private ThirdPartyClass _obj;
public BaseClass(int i) { _obj = new ThirdPartyClass(i); }
public int SomeProperty
{
get { return _obj.SomeProperty; }
set { _obj.SomeProperty = value; }
}
public int SomeMethod(string val) { return _obj.SomeMethod(val); }
public static SomeStaticMethod() { ThirdPartyClass.SomeStaticMethod(); }
}
// The child class that inherits from the "base" BaseClass
public class ChildClass : BaseClass
{
}
First of all, this might be a logical problem. What if you are going to extend a sealed class? Or Int32 class? Delegate?
Anyway, the way I recommend is to create an interface and implement all the functions you need in the subclass.
Is there a syntax trick to get to the constant in a generic class without specifying an (ad-hoc) type?
public class MyClass<T>{
public const string MyConstant = "fortytwo";
}
// I try to avoid this type specification.
var doeswork = MyClass<object>.MyConstant;
// Syntax similar to what I'd like to accomplish.
var doesnotwork = MyClass.MyConstant;
There is a caveat about the static variable (constant) not being shared between different types like MyClass<object> and MyClass<int> but my question is about possible available syntax trick.
Use a non-generic abstract parent class.
public abstract class MyClass
{
public const string MyConstant = "fortytwo";
}
public class MyClass<T> : MyClass
{
// stuff
}
var doeswork = MyClass.MyConstant;
That of course assumes that there's some reason the constant needs to be part of the generic class; if it has public accessibility, I'm not seeing a reason why you wouldn't just put it in a separate class.
Having a non-generic abstract parent class is a good idea for every generic class you make; the generic class is actually a template for the specific subtype classes, rather than a true parent, so having a true non-generic parent can make some techniques (such as, but certainly not limited to, this one) a lot easier.
Something like this works:
using System;
namespace Demo
{
public class MyClass // Use a non-generic base class for the non-generic bits.
{
public const string MyConstant = "fortytwo";
public static string MyString()
{
return MyConstant;
}
}
public class MyClass<T>: MyClass // Derive the generic class
{ // from the non-generic one.
public void Test(T item)
{
Console.WriteLine(MyConstant);
Console.WriteLine(item);
}
}
public static class Program
{
private static void Main()
{
Console.WriteLine(MyClass.MyConstant);
Console.WriteLine(MyClass.MyString());
}
}
}
This approach works for any static types or values that you want to provide which do not depend on the type parameter. It also works with static methods too.
(Note: If you don't want anybody to instantiate the base class, make it abstract.)
I have the following class definition:
public abstract class BaseExample<T> where T : BaseExample<T>
{
public abstract T Clone(T original);
}
and its inheritances
public class Example01 : BaseExample<Example01>
{
public override Example01 Clone(Example01 original)
{
return this; // not the actual implementation
}
}
public class Example02 : BaseExample<Example02>
{
public override Example02 Clone(Example02 original)
{
return this; // not the actual implementation
}
}
How to declare a variable with the type or the base class? Since the following declaration doesn't compile:
private BaseExample<T> declarationA;
private BaseExample<T> declarationA;
private BaseExample declarationB;
It won't work as whatever you assign to generic type T cannot really ever be BaseExample<T>.
BaseExample<int> declarationA;
in case above int can't really be BaseExample<int> (int != BaseExample<int>)
I need to have a instance of BaseExample that could receive both Example01 or Example02 values. e.g.: BaseExample a = new Example01()
You can't - BaseExample<Example01> and BaseExample<Example02> are different types. There's not a base type (other than object) that could hold either type.
Suppose you could:
BaseExample a = new Example01();
what would the return type of a.Clone() return?
If your code is within a generic class ot method, then you could:
public T MyMethod<T>(T value) where T : BaseExample<T>
{
BaseExample<T> a = value;
return value.Close();
}
But you'd then have to specify the type when calling the method, e.g.
Example01 a1 = new Example01();
Example01 a2 = MyMethod(a1); // MyMethod<Example01> is inferred by the compiler
As mentioned, because Generic<T1> and Generic<T2> are different classes, you cannot assign them to the same variable.
One way I get around this is to use a non-generic base class, such that
public abstract class BaseExample { ... }
public abstract class BaseExmmple<T> : BaseExample
where T : BaseExample<T>
{ ... }
This can be made more safe by implementing an internal abstract member, such that outside classes cannot implement BaseExample.
If you wish to be able to call .Clone() from an object held in a variable of the non-generic type, you should implement an object-returning form which is wrapped by the generic class to call the generic form.
Example:
namespace MyProgram.Testing
{
public class Test1
{
public void TestMethod()
{
String actualType = this.GetType().FullName.ToString();
return;
}
public static String GetInheritedClassName()
{
return System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.FullName;
}
}
public class Test2 : Test1
{
}
public class Test3
{
String test2ClassName = Test2.GetInheritedClassName();
}
}
Anyway, I want it to return "MyProgram.Testing.Test2" but instead Test2.GetInheritedClassName() returns "MyProgram.Testing.Test1". What do I have to put into that static class to get it to return that (if possible)?
It's not possible. When you call Test2.GetInheritedClassName, it's actually Test1.GetInheritedClassName that is called, because Test2.GetInheritedClassName doesn't really exists (btw, some tools like Resharper would show a warning: Access to a static member of a type via a derived type)
Static members don't participate in inheritance, which is kind of logical since inheritance only makes sense when you're dealing with instances...
The code that's printing out the type is the base-class method. Except for rare Reflection scenarios such as you provide above, execution wouldn't be affected by whether the method is called using the derived type or the base type, so the system makes no distinction.
You could, however, get around this by defining a generic base type:
class ClassNameTesterBase<T>where T:ClassNameTester<T>
{
public static String getName() { return (typeof(T)).Name; }
}
and then defining the other types of interest:
class ClassNameTester1<T> : ClassNameTesterBase<T> ...
class ClassNameTester2<T> : ClassNameTester1<T> ...
One may then if desired define leaf classes:
class ClassNameTester1 : ClassNameTester1<ClassNameTester1> { }
class ClassNameTester2 : ClassNameTester2<ClassNameTester2> { }
One slight caveat here is that ClassNameTester2 derives its innards from from ClassNameTester1<T> but is not substitutable for anything having to do with the ClassNameTester1<ClassNameTester1>; if it's being used as a static class, though, that shouldn't be a problem.